生成子进程

Spawning subprocesses

Trio 提供了支持生成其他程序作为子进程、通过管道与它们通信、发送信号并等待它们退出的功能。

大多数情况下,这通过我们的高级接口 trio.run_process() 来完成。它允许您运行一个进程直到完成,同时可选地捕获输出,或者将其运行在后台任务中,并在进程运行时与之交互:

await trio.run_process(command, *, stdin=b'', capture_stdout=False, capture_stderr=False, check=True, deliver_cancel=None, task_status=TASK_STATUS_IGNORED, **options)

Run command in a subprocess and wait for it to complete.

This function can be called in two different ways.

One option is a direct call, like:

completed_process_info = await trio.run_process(...)

In this case, it returns a subprocess.CompletedProcess instance describing the results. Use this if you want to treat a process like a function call.

The other option is to run it as a task using Nursery.start – the enhanced version of ~Nursery.start_soon that lets a task pass back a value during startup:

process = await nursery.start(trio.run_process, ...)

In this case, ~Nursery.start returns a Process object that you can use to interact with the process while it's running. Use this if you want to treat a process like a background task.

Either way, run_process makes sure that the process has exited before returning, handles cancellation, optionally checks for errors, and provides some convenient shorthands for dealing with the child's input/output.

Input: run_process supports all the same stdin= arguments as subprocess.Popen. In addition, if you simply want to pass in some fixed data, you can pass a plain bytes object, and run_process will take care of setting up a pipe, feeding in the data you gave, and then sending end-of-file. The default is b"", which means that the child will receive an empty stdin. If you want the child to instead read from the parent's stdin, use stdin=None.

Output: By default, any output produced by the subprocess is passed through to the standard output and error streams of the parent Trio process.

When calling run_process directly, you can capture the subprocess's output by passing capture_stdout=True to capture the subprocess's standard output, and/or capture_stderr=True to capture its standard error. Captured data is collected up by Trio into an in-memory buffer, and then provided as the stdout and/or stderr attributes of the returned CompletedProcess object. The value for any stream that was not captured will be None.

If you want to capture both stdout and stderr while keeping them separate, pass capture_stdout=True, capture_stderr=True.

If you want to capture both stdout and stderr but mixed together in the order they were printed, use: capture_stdout=True, stderr=subprocess.STDOUT. This directs the child's stderr into its stdout, so the combined output will be available in the ~subprocess.CompletedProcess.stdout attribute.

If you're using await nursery.start(trio.run_process, ...) and want to capture the subprocess's output for further processing, then use stdout=subprocess.PIPE and then make sure to read the data out of the Process.stdout stream. If you want to capture stderr separately, use stderr=subprocess.PIPE. If you want to capture both, but mixed together in the correct order, use stdout=subprocess.PIPE, stderr=subprocess.STDOUT.

Error checking: If the subprocess exits with a nonzero status code, indicating failure, run_process() raises a subprocess.CalledProcessError exception rather than returning normally. The captured outputs are still available as the stdout and stderr attributes of that exception. To disable this behavior, so that run_process() returns normally even if the subprocess exits abnormally, pass check=False.

Note that this can make the capture_stdout and capture_stderr arguments useful even when starting run_process as a task: if you only care about the output if the process fails, then you can enable capturing and then read the output off of the ~subprocess.CalledProcessError.

Cancellation: If cancelled, run_process sends a termination request to the subprocess, then waits for it to fully exit. The deliver_cancel argument lets you control how the process is terminated.

备注

run_process is intentionally similar to the standard library subprocess.run, but some of the defaults are different. Specifically, we default to:

To get the subprocess.run semantics, use check=False, stdin=None.

参数:
  • command (list or str) -- The command to run. Typically this is a sequence of strings such as ['ls', '-l', 'directory with spaces'], where the first element names the executable to invoke and the other elements specify its arguments. With shell=True in the **options, or on Windows, command may alternatively be a string, which will be parsed following platform-dependent quoting rules.

  • stdin (bytes, subprocess.PIPE, file descriptor, or None) --

    The bytes to provide to the subprocess on its standard input stream, or None if the subprocess's standard input should come from the same place as the parent Trio process's standard input. As is the case with the subprocess module, you can also pass a file descriptor or an object with a fileno() method, in which case the subprocess's standard input will come from that file.

    When starting run_process as a background task, you can also use stdin=subprocess.PIPE, in which case Process.stdin will be a ~trio.abc.SendStream that you can use to send data to the child.

  • capture_stdout (bool) -- If true, capture the bytes that the subprocess writes to its standard output stream and return them in the ~subprocess.CompletedProcess.stdout attribute of the returned subprocess.CompletedProcess or subprocess.CalledProcessError.

  • capture_stderr (bool) -- If true, capture the bytes that the subprocess writes to its standard error stream and return them in the ~subprocess.CompletedProcess.stderr attribute of the returned ~subprocess.CompletedProcess or subprocess.CalledProcessError.

  • check (bool) -- If false, don't validate that the subprocess exits successfully. You should be sure to check the returncode attribute of the returned object if you pass check=False, so that errors don't pass silently.

  • deliver_cancel (async function or None) --

    If run_process is cancelled, then it needs to kill the child process. There are multiple ways to do this, so we let you customize it.

    If you pass None (the default), then the behavior depends on the platform:

    • On Windows, Trio calls TerminateProcess, which should kill the process immediately.

    • On Unix-likes, the default behavior is to send a SIGTERM, wait 5 seconds, and send a SIGKILL.

    Alternatively, you can customize this behavior by passing in an arbitrary async function, which will be called with the Process object as an argument. For example, the default Unix behavior could be implemented like this:

    async def my_deliver_cancel(process):
        process.send_signal(signal.SIGTERM)
        await trio.sleep(5)
        process.send_signal(signal.SIGKILL)
    

    When the process actually exits, the deliver_cancel function will automatically be cancelled – so if the process exits after SIGTERM, then we'll never reach the SIGKILL.

    In any case, run_process will always wait for the child process to exit before raising Cancelled.

  • **options (object) -- run_process() also accepts any general subprocess options and passes them on to the Process constructor. This includes the stdout and stderr options, which provide additional redirection possibilities such as stderr=subprocess.STDOUT, stdout=subprocess.DEVNULL, or file descriptors.

返回类型:

subprocess.CompletedProcess[bytes]

返回:

When called normally – a subprocess.CompletedProcess instance describing the return code and outputs.

When called via Nursery.start – a trio.Process instance.

抛出:
  • UnicodeError -- if stdin is specified as a Unicode string, rather than bytes

  • ValueError -- if multiple redirections are specified for the same stream, e.g., both capture_stdout=True and stdout=subprocess.DEVNULL

  • subprocess.CalledProcessError -- if check=False is not passed and the process exits with a nonzero exit status

  • OSError -- if an error is encountered starting or communicating with the process

  • ExceptionGroup -- if exceptions occur in deliver_cancel, or when exceptions occur when communicating with the subprocess. If strict_exception_groups is set to false in the global context, which is deprecated, then single exceptions will be collapsed.

备注

The child process runs in the same process group as the parent Trio process, so a Ctrl+C will be delivered simultaneously to both parent and child. If you don't want this behavior, consult your platform's documentation for starting child processes in a different process group.

class trio._subprocess.HasFileno(Protocol)

基类:Protocol

Represents any file-like object that has a file descriptor.

fileno()
返回类型:

int

trio._subprocess.StrOrBytesPath

str | bytes | PathLike[str] | PathLike[bytes] 的别名

class trio.Process(popen, stdin, stdout, stderr)

基类:object

A child process. Like subprocess.Popen, but async.

This class has no public constructor. The most common way to get a Process object is to combine Nursery.start with run_process:

process_object = await nursery.start(run_process, ...)

This way, run_process supervises the process and makes sure that it is cleaned up properly, while optionally checking the return value, feeding it input, and so on.

If you need more control – for example, because you want to spawn a child process that outlives your program – then another option is to use trio.lowlevel.open_process:

process_object = await trio.lowlevel.open_process(...)
args

The command passed at construction time, specifying the process to execute and its arguments.

Type:

str or list

pid

The process ID of the child process managed by this object.

Type:

int

stdin

A stream connected to the child's standard input stream: when you write bytes here, they become available for the child to read. Only available if the Process was constructed using stdin=PIPE; otherwise this will be None.

Type:

trio.abc.SendStream or None

stdout

A stream connected to the child's standard output stream: when the child writes to standard output, the written bytes become available for you to read here. Only available if the Process was constructed using stdout=PIPE; otherwise this will be None.

Type:

trio.abc.ReceiveStream or None

stderr

A stream connected to the child's standard error stream: when the child writes to standard error, the written bytes become available for you to read here. Only available if the Process was constructed using stderr=PIPE; otherwise this will be None.

Type:

trio.abc.ReceiveStream or None

stdio

A stream that sends data to the child's standard input and receives from the child's standard output. Only available if both stdin and stdout are available; otherwise this will be None.

Type:

trio.StapledStream or None

returncode

The exit status of the process (an integer), or None if it's still running.

By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (SIGSEGV). On Windows, a process that exits due to a call to Process.terminate() will have an exit status of 1.

Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.

await wait()

Block until the process exits.

返回类型:

int

返回:

The exit status of the process; see returncode.

poll()

Returns the exit status of the process (an integer), or None if it's still running.

Note that on Trio (unlike the standard library subprocess.Popen), process.poll() and process.returncode always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.

返回类型:

int | None

kill()

Immediately terminate the process.

On UNIX, this is equivalent to send_signal(signal.SIGKILL). On Windows, it calls TerminateProcess. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; use wait() if you want to ensure the process is actually dead before proceeding.

返回类型:

None

terminate()

Terminate the process, politely if possible.

On UNIX, this is equivalent to send_signal(signal.SIGTERM); by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows, terminate() forcibly terminates the process in the same manner as kill().

返回类型:

None

send_signal(sig)

Send signal sig to the process.

On UNIX, sig may be any signal defined in the signal module, such as signal.SIGINT or signal.SIGTERM. On Windows, it may be anything accepted by the standard library subprocess.Popen.send_signal().

返回类型:

None

备注

communicate() 不是 Process 对象上的方法;对于简单的捕获,正常调用 run_process(),或者如果您有特殊需求,可以自己编写循环。 communicate() 在标准库中有非常不寻常的取消行为(在某些平台上,它会生成一个后台线程,在超时过期后仍然继续从子进程读取),我们希望提供一个更少惊讶的接口。

kill()

Immediately terminate the process.

On UNIX, this is equivalent to send_signal(signal.SIGKILL). On Windows, it calls TerminateProcess. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; use wait() if you want to ensure the process is actually dead before proceeding.

返回类型:

None

poll()

Returns the exit status of the process (an integer), or None if it's still running.

Note that on Trio (unlike the standard library subprocess.Popen), process.poll() and process.returncode always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.

返回类型:

int | None

property returncode: int | None

The exit status of the process (an integer), or None if it's still running.

By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (SIGSEGV). On Windows, a process that exits due to a call to Process.terminate() will have an exit status of 1.

Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.

send_signal(sig)

Send signal sig to the process.

On UNIX, sig may be any signal defined in the signal module, such as signal.SIGINT or signal.SIGTERM. On Windows, it may be anything accepted by the standard library subprocess.Popen.send_signal().

返回类型:

None

terminate()

Terminate the process, politely if possible.

On UNIX, this is equivalent to send_signal(signal.SIGTERM); by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows, terminate() forcibly terminates the process in the same manner as kill().

返回类型:

None

await wait()

Block until the process exits.

返回类型:

int

返回:

The exit status of the process; see returncode.

如果 trio.run_process() 太有限制,我们还提供了一个低级 API, trio.lowlevel.open_process()。例如,如果您想生成一个将比父进程生命周期更长并且会成为孤儿的子进程,那么 run_process() 做不到这一点,但 open_process() 可以。

Trio provides support for spawning other programs as subprocesses, communicating with them via pipes, sending them signals, and waiting for them to exit.

Most of the time, this is done through our high-level interface, trio.run_process(). It lets you either run a process to completion while optionally capturing the output, or else run it in a background task and interact with it while it's running:

await trio.run_process(command, *, stdin=b'', capture_stdout=False, capture_stderr=False, check=True, deliver_cancel=None, task_status=TASK_STATUS_IGNORED, **options)

Run command in a subprocess and wait for it to complete.

This function can be called in two different ways.

One option is a direct call, like:

completed_process_info = await trio.run_process(...)

In this case, it returns a subprocess.CompletedProcess instance describing the results. Use this if you want to treat a process like a function call.

The other option is to run it as a task using Nursery.start – the enhanced version of ~Nursery.start_soon that lets a task pass back a value during startup:

process = await nursery.start(trio.run_process, ...)

In this case, ~Nursery.start returns a Process object that you can use to interact with the process while it's running. Use this if you want to treat a process like a background task.

Either way, run_process makes sure that the process has exited before returning, handles cancellation, optionally checks for errors, and provides some convenient shorthands for dealing with the child's input/output.

Input: run_process supports all the same stdin= arguments as subprocess.Popen. In addition, if you simply want to pass in some fixed data, you can pass a plain bytes object, and run_process will take care of setting up a pipe, feeding in the data you gave, and then sending end-of-file. The default is b"", which means that the child will receive an empty stdin. If you want the child to instead read from the parent's stdin, use stdin=None.

Output: By default, any output produced by the subprocess is passed through to the standard output and error streams of the parent Trio process.

When calling run_process directly, you can capture the subprocess's output by passing capture_stdout=True to capture the subprocess's standard output, and/or capture_stderr=True to capture its standard error. Captured data is collected up by Trio into an in-memory buffer, and then provided as the stdout and/or stderr attributes of the returned CompletedProcess object. The value for any stream that was not captured will be None.

If you want to capture both stdout and stderr while keeping them separate, pass capture_stdout=True, capture_stderr=True.

If you want to capture both stdout and stderr but mixed together in the order they were printed, use: capture_stdout=True, stderr=subprocess.STDOUT. This directs the child's stderr into its stdout, so the combined output will be available in the ~subprocess.CompletedProcess.stdout attribute.

If you're using await nursery.start(trio.run_process, ...) and want to capture the subprocess's output for further processing, then use stdout=subprocess.PIPE and then make sure to read the data out of the Process.stdout stream. If you want to capture stderr separately, use stderr=subprocess.PIPE. If you want to capture both, but mixed together in the correct order, use stdout=subprocess.PIPE, stderr=subprocess.STDOUT.

Error checking: If the subprocess exits with a nonzero status code, indicating failure, run_process() raises a subprocess.CalledProcessError exception rather than returning normally. The captured outputs are still available as the stdout and stderr attributes of that exception. To disable this behavior, so that run_process() returns normally even if the subprocess exits abnormally, pass check=False.

Note that this can make the capture_stdout and capture_stderr arguments useful even when starting run_process as a task: if you only care about the output if the process fails, then you can enable capturing and then read the output off of the ~subprocess.CalledProcessError.

Cancellation: If cancelled, run_process sends a termination request to the subprocess, then waits for it to fully exit. The deliver_cancel argument lets you control how the process is terminated.

备注

run_process is intentionally similar to the standard library subprocess.run, but some of the defaults are different. Specifically, we default to:

To get the subprocess.run semantics, use check=False, stdin=None.

参数:
  • command (list or str) -- The command to run. Typically this is a sequence of strings such as ['ls', '-l', 'directory with spaces'], where the first element names the executable to invoke and the other elements specify its arguments. With shell=True in the **options, or on Windows, command may alternatively be a string, which will be parsed following platform-dependent quoting rules.

  • stdin (bytes, subprocess.PIPE, file descriptor, or None) --

    The bytes to provide to the subprocess on its standard input stream, or None if the subprocess's standard input should come from the same place as the parent Trio process's standard input. As is the case with the subprocess module, you can also pass a file descriptor or an object with a fileno() method, in which case the subprocess's standard input will come from that file.

    When starting run_process as a background task, you can also use stdin=subprocess.PIPE, in which case Process.stdin will be a ~trio.abc.SendStream that you can use to send data to the child.

  • capture_stdout (bool) -- If true, capture the bytes that the subprocess writes to its standard output stream and return them in the ~subprocess.CompletedProcess.stdout attribute of the returned subprocess.CompletedProcess or subprocess.CalledProcessError.

  • capture_stderr (bool) -- If true, capture the bytes that the subprocess writes to its standard error stream and return them in the ~subprocess.CompletedProcess.stderr attribute of the returned ~subprocess.CompletedProcess or subprocess.CalledProcessError.

  • check (bool) -- If false, don't validate that the subprocess exits successfully. You should be sure to check the returncode attribute of the returned object if you pass check=False, so that errors don't pass silently.

  • deliver_cancel (async function or None) --

    If run_process is cancelled, then it needs to kill the child process. There are multiple ways to do this, so we let you customize it.

    If you pass None (the default), then the behavior depends on the platform:

    • On Windows, Trio calls TerminateProcess, which should kill the process immediately.

    • On Unix-likes, the default behavior is to send a SIGTERM, wait 5 seconds, and send a SIGKILL.

    Alternatively, you can customize this behavior by passing in an arbitrary async function, which will be called with the Process object as an argument. For example, the default Unix behavior could be implemented like this:

    async def my_deliver_cancel(process):
        process.send_signal(signal.SIGTERM)
        await trio.sleep(5)
        process.send_signal(signal.SIGKILL)
    

    When the process actually exits, the deliver_cancel function will automatically be cancelled – so if the process exits after SIGTERM, then we'll never reach the SIGKILL.

    In any case, run_process will always wait for the child process to exit before raising Cancelled.

  • **options (object) -- run_process() also accepts any general subprocess options and passes them on to the Process constructor. This includes the stdout and stderr options, which provide additional redirection possibilities such as stderr=subprocess.STDOUT, stdout=subprocess.DEVNULL, or file descriptors.

返回类型:

CompletedProcess[bytes]

返回:

When called normally – a subprocess.CompletedProcess instance describing the return code and outputs.

When called via Nursery.start – a trio.Process instance.

抛出:
  • UnicodeError -- if stdin is specified as a Unicode string, rather than bytes

  • ValueError -- if multiple redirections are specified for the same stream, e.g., both capture_stdout=True and stdout=subprocess.DEVNULL

  • subprocess.CalledProcessError -- if check=False is not passed and the process exits with a nonzero exit status

  • OSError -- if an error is encountered starting or communicating with the process

  • ExceptionGroup -- if exceptions occur in deliver_cancel, or when exceptions occur when communicating with the subprocess. If strict_exception_groups is set to false in the global context, which is deprecated, then single exceptions will be collapsed.

备注

The child process runs in the same process group as the parent Trio process, so a Ctrl+C will be delivered simultaneously to both parent and child. If you don't want this behavior, consult your platform's documentation for starting child processes in a different process group.

class trio._subprocess.HasFileno(Protocol)

基类:Protocol

Represents any file-like object that has a file descriptor.

fileno()
返回类型:

int

trio._subprocess.StrOrBytesPath

str | bytes | PathLike[str] | PathLike[bytes] 的别名

class trio.Process(popen, stdin, stdout, stderr)

基类:object

A child process. Like subprocess.Popen, but async.

This class has no public constructor. The most common way to get a Process object is to combine Nursery.start with run_process:

process_object = await nursery.start(run_process, ...)

This way, run_process supervises the process and makes sure that it is cleaned up properly, while optionally checking the return value, feeding it input, and so on.

If you need more control – for example, because you want to spawn a child process that outlives your program – then another option is to use trio.lowlevel.open_process:

process_object = await trio.lowlevel.open_process(...)
args

The command passed at construction time, specifying the process to execute and its arguments.

Type:

str or list

pid

The process ID of the child process managed by this object.

Type:

int

stdin

A stream connected to the child's standard input stream: when you write bytes here, they become available for the child to read. Only available if the Process was constructed using stdin=PIPE; otherwise this will be None.

Type:

trio.abc.SendStream or None

stdout

A stream connected to the child's standard output stream: when the child writes to standard output, the written bytes become available for you to read here. Only available if the Process was constructed using stdout=PIPE; otherwise this will be None.

Type:

trio.abc.ReceiveStream or None

stderr

A stream connected to the child's standard error stream: when the child writes to standard error, the written bytes become available for you to read here. Only available if the Process was constructed using stderr=PIPE; otherwise this will be None.

Type:

trio.abc.ReceiveStream or None

stdio

A stream that sends data to the child's standard input and receives from the child's standard output. Only available if both stdin and stdout are available; otherwise this will be None.

Type:

trio.StapledStream or None

returncode

The exit status of the process (an integer), or None if it's still running.

By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (SIGSEGV). On Windows, a process that exits due to a call to Process.terminate() will have an exit status of 1.

Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.

await wait()

Block until the process exits.

返回类型:

int

返回:

The exit status of the process; see returncode.

poll()

Returns the exit status of the process (an integer), or None if it's still running.

Note that on Trio (unlike the standard library subprocess.Popen), process.poll() and process.returncode always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.

返回类型:

int | None

kill()

Immediately terminate the process.

On UNIX, this is equivalent to send_signal(signal.SIGKILL). On Windows, it calls TerminateProcess. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; use wait() if you want to ensure the process is actually dead before proceeding.

返回类型:

None

terminate()

Terminate the process, politely if possible.

On UNIX, this is equivalent to send_signal(signal.SIGTERM); by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows, terminate() forcibly terminates the process in the same manner as kill().

返回类型:

None

send_signal(sig)

Send signal sig to the process.

On UNIX, sig may be any signal defined in the signal module, such as signal.SIGINT or signal.SIGTERM. On Windows, it may be anything accepted by the standard library subprocess.Popen.send_signal().

返回类型:

None

备注

communicate() is not provided as a method on Process objects; call run_process() normally for simple capturing, or write the loop yourself if you have unusual needs. communicate() has quite unusual cancellation behavior in the standard library (on some platforms it spawns a background thread which continues to read from the child process even after the timeout has expired) and we wanted to provide an interface with fewer surprises.

kill()

Immediately terminate the process.

On UNIX, this is equivalent to send_signal(signal.SIGKILL). On Windows, it calls TerminateProcess. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; use wait() if you want to ensure the process is actually dead before proceeding.

返回类型:

None

poll()

Returns the exit status of the process (an integer), or None if it's still running.

Note that on Trio (unlike the standard library subprocess.Popen), process.poll() and process.returncode always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.

返回类型:

int | None

property returncode: int | None

The exit status of the process (an integer), or None if it's still running.

By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (SIGSEGV). On Windows, a process that exits due to a call to Process.terminate() will have an exit status of 1.

Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.

send_signal(sig)

Send signal sig to the process.

On UNIX, sig may be any signal defined in the signal module, such as signal.SIGINT or signal.SIGTERM. On Windows, it may be anything accepted by the standard library subprocess.Popen.send_signal().

返回类型:

None

terminate()

Terminate the process, politely if possible.

On UNIX, this is equivalent to send_signal(signal.SIGTERM); by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows, terminate() forcibly terminates the process in the same manner as kill().

返回类型:

None

await wait()

Block until the process exits.

返回类型:

int

返回:

The exit status of the process; see returncode.

If trio.run_process is too limiting, we also offer a low-level API, trio.lowlevel.open_process. For example, if you want to spawn a child process that will outlive the parent process and be orphaned, then ~trio.run_process can't do that, but ~trio.lowlevel.open_process can.

启动子进程的选项

Options for starting subprocesses

Trio 的所有子进程 API 都接受标准 subprocess 模块使用的众多关键字参数,用于控制进程启动的环境以及与之通信的机制。这些参数可以在以下文档中看到 **options 时传递。请参见 subprocess 文档中的 完整列表 或者 常用参数 。(您可能需要 import subprocess 才能访问像 PIPEDEVNULL 这样的常量。)

目前,Trio 始终使用无缓冲的字节流与进程通信,因此不支持 encodingerrorsuniversal_newlines (别名 text )和 bufsize 选项。

All of Trio's subprocess APIs accept the numerous keyword arguments used by the standard subprocess module to control the environment in which a process starts and the mechanisms used for communicating with it. These may be passed wherever you see **options in the documentation below. See the full list or just the frequently used ones in the subprocess documentation. (You may need to import subprocess in order to access constants such as PIPE or DEVNULL.)

Currently, Trio always uses unbuffered byte streams for communicating with a process, so it does not support the encoding, errors, universal_newlines (alias text), and bufsize options.

引用:比您想知道的更多

Quoting: more than you wanted to know

Trio 的子进程 API 通常需要将要运行的命令及其参数作为字符串序列传递,其中序列的第一个元素指定要运行的命令,剩余的元素指定命令的参数,每个参数占一个元素。采用这种形式是因为它可以避免潜在的引号陷阱;例如,你可以运行 ["cp", "-f", source_file, dest_file],而无需担心 source_filedest_file 是否包含空格。

如果你只在 UNIX 上运行不使用 shell=True 的子进程,那么指定命令时只需知道这些。如果你使用 shell=True 或在 Windows 上运行,可能需要阅读本节的其余部分,以便了解潜在的陷阱。

在 UNIX 上使用 shell=True 时,必须将命令指定为一个单一字符串,这个字符串将被传递给 shell,类似于你在交互式提示符下输入的方式。这个选项的优点是它允许你使用 shell 功能,比如管道和重定向,而不需要编写处理它们的代码。例如,你可以写 Process("ls | grep some_string", shell=True)。缺点是你必须考虑到 shell 的引用规则,通常需要通过 shlex.quote() 来包装可能包含空格、引号或其他 shell 元字符的任何参数。如果你不这样做,那么看似安全的 f"ls | grep {some_string}" 在调用时,若 some_string = "foo; rm -rf /",可能会导致灾难。

在 Windows 上,进程生成的基本 API(CreateProcess() 系统调用)接受一个字符串而不是列表,实际上是子进程决定如何将这个字符串拆分为单独的参数。由于 C 语言规定 main() 应该接受一个参数列表,大多数 你遇到的程序将遵循 Microsoft C/C++ 运行时使用的规则。subprocess.Popen,因此 Trio 也使用这些规则将参数序列转换为字符串,这些规则在 subprocess 模块中有 文档记录。没有文档化的 Python 标准库函数可以直接执行该转换,因此即使在 Windows 上,你几乎总是需要传递参数序列而不是字符串。但如果你启动的程序不能按标准方式将命令行拆分回单独的参数,那么你可能需要传递一个字符串来解决这个问题。(或者你可能只是运气不好:据我所知,Windows 批处理文件没有办法传递包含双引号的参数。)

在 Windows 上使用 shell=True 时,情况变得更加混乱。现在,有两个独立的引用规则应用:一个由 Windows 命令 shell CMD.EXE 使用,另一个由被启动的进程使用,而且它们是 不同的。(而且没有 shlex.quote() 来帮助你:它使用 UNIX 风格的引用规则,即使在 Windows 上也是如此。)大多数由 shell 解释的特殊字符 &<>()^| 如果 shell 认为它们在双引号内,则不被视为特殊字符,但 %FOO% 环境变量替换仍然有效,而且 shell 没有提供在双引号字符串内写入双引号的办法。双引号外部,任何字符(包括双引号)都可以使用前导 ^ 来转义。但由于管道通过在子 shell 中运行每个命令来处理,因此可能需要多层转义:

echo ^^^&x | find "x" | find "x"          # prints: &x

如果你将管道与 () 分组结合使用,可能需要更多层的转义:

(echo ^^^^^^^&x | find "x") | find "x"    # prints: &x

由于进程创建接受一个字符串参数,CMD.EXE 的引用规则不会影响单词拆分,并且在 CMD.EXE 扩展过程中不会删除双引号。双引号很麻烦,因为 CMD.EXE 处理它们的方式与 MSVC 运行时规则不同;例如:

prog.exe "foo \"bar\" baz"

程序会看到一个参数 foo "bar" baz,但 CMD.EXE 认为 bar\ 没有被引用,而 foo \baz 被认为是引用的。所有这些使得在 Windows 上可靠地插入任何内容到 shell=True 命令行中变得非常困难,Trio 退回到 subprocess 的行为:如果你传递一个包含 shell=True 的序列,它会像 shell=False 一样进行引用,并且最好不要包含你未计划使用的任何 shell 元字符。

进一步阅读:

The command to run and its arguments usually must be passed to Trio's subprocess APIs as a sequence of strings, where the first element in the sequence specifies the command to run and the remaining elements specify its arguments, one argument per element. This form is used because it avoids potential quoting pitfalls; for example, you can run ["cp", "-f", source_file, dest_file] without worrying about whether source_file or dest_file contains spaces.

If you only run subprocesses without shell=True and on UNIX, that's all you need to know about specifying the command. If you use shell=True or run on Windows, you probably should read the rest of this section to be aware of potential pitfalls.

With shell=True on UNIX, you must specify the command as a single string, which will be passed to the shell as if you'd entered it at an interactive prompt. The advantage of this option is that it lets you use shell features like pipes and redirection without writing code to handle them. For example, you can write Process("ls | grep some_string", shell=True). The disadvantage is that you must account for the shell's quoting rules, generally by wrapping in shlex.quote() any argument that might contain spaces, quotes, or other shell metacharacters. If you don't do that, your safe-looking f"ls | grep {some_string}" might end in disaster when invoked with some_string = "foo; rm -rf /".

On Windows, the fundamental API for process spawning (the CreateProcess() system call) takes a string, not a list, and it's actually up to the child process to decide how it wants to split that string into individual arguments. Since the C language specifies that main() should take a list of arguments, most programs you encounter will follow the rules used by the Microsoft C/C++ runtime. subprocess.Popen, and thus also Trio, uses these rules when it converts an argument sequence to a string, and they are documented alongside the subprocess module. There is no documented Python standard library function that can directly perform that conversion, so even on Windows, you almost always want to pass an argument sequence rather than a string. But if the program you're spawning doesn't split its command line back into individual arguments in the standard way, you might need to pass a string to work around this. (Or you might just be out of luck: as far as I can tell, there's simply no way to pass an argument containing a double-quote to a Windows batch file.)

On Windows with shell=True, things get even more chaotic. Now there are two separate sets of quoting rules applied, one by the Windows command shell CMD.EXE and one by the process being spawned, and they're different. (And there's no shlex.quote() to save you: it uses UNIX-style quoting rules, even on Windows.) Most special characters interpreted by the shell &<>()^| are not treated as special if the shell thinks they're inside double quotes, but %FOO% environment variable substitutions still are, and the shell doesn't provide any way to write a double quote inside a double-quoted string. Outside double quotes, any character (including a double quote) can be escaped using a leading ^. But since a pipeline is processed by running each command in the pipeline in a subshell, multiple layers of escaping can be needed:

echo ^^^&x | find "x" | find "x"          # prints: &x

And if you combine pipelines with () grouping, you can need even more levels of escaping:

(echo ^^^^^^^&x | find "x") | find "x"    # prints: &x

Since process creation takes a single arguments string, CMD.EXE's quoting does not influence word splitting, and double quotes are not removed during CMD.EXE's expansion pass. Double quotes are troublesome because CMD.EXE handles them differently from the MSVC runtime rules; in:

prog.exe "foo \"bar\" baz"

the program will see one argument foo "bar" baz but CMD.EXE thinks bar\ is not quoted while foo \ and baz are. All of this makes it a formidable task to reliably interpolate anything into a shell=True command line on Windows, and Trio falls back on the subprocess behavior: If you pass a sequence with shell=True, it's quoted in the same way as a sequence with shell=False, and had better not contain any shell metacharacters you weren't planning on.

Further reading: