Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions executor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def execute(*command, **options):
nonzero exit code (and :attr:`~ExternalCommand.check` is
:data:`True`).

If :attr:`~ExternalCommand.async` is :data:`True` then :func:`execute()`
If :attr:`~ExternalCommand.asynchronous` is :data:`True` then :func:`execute()`
will automatically start the external command for you using
:func:`~ExternalCommand.start()` (but it won't wait for it to end). If you
want to create an :class:`ExternalCommand` object instance without
Expand Down Expand Up @@ -183,7 +183,7 @@ def execute_prepared(command):
example :class:`.RemoteCommand`).
:returns: The return value of this function depends on several options:

- If :attr:`~ExternalCommand.async` is :data:`True` the
- If :attr:`~ExternalCommand.asynchronous` is :data:`True` the
constructed :class:`ExternalCommand` object is returned.

- If :attr:`~ExternalCommand.callback` is set the value of
Expand All @@ -196,7 +196,7 @@ def execute_prepared(command):
returned.
:raises: See :func:`execute()` and :func:`.remote()`.
"""
if command.async:
if command.asynchronous:
command.start()
return command
else:
Expand Down Expand Up @@ -265,7 +265,7 @@ def __init__(self, *command, **options):
:param command: Any positional arguments are converted to a list and
used to set :attr:`command`.
:param options: Keyword arguments can be used to conveniently override
the default values of :attr:`async`, :attr:`callback`,
the default values of :attr:`asynchronous`, :attr:`callback`,
:attr:`capture`, :attr:`capture_stderr`, :attr:`check`,
:attr:`directory`, :attr:`encoding`,
:attr:`environment`, :attr:`fakeroot`, :attr:`input`,
Expand All @@ -291,7 +291,7 @@ def __init__(self, *command, **options):
self.stderr_stream = CachedStream(self, 'stderr')

@mutable_property
def async(self):
def asynchronous(self):
"""
Enable asynchronous command execution.

Expand Down Expand Up @@ -330,19 +330,19 @@ def buffer_size(self):
The value of :attr:`buffer_size` becomes the `bufsize` argument
that's passed to :class:`subprocess.Popen` by :func:`start()`.

If :data:`async` is :data:`True` and :attr:`buffered` is :data:`False`
If :data:`asynchronous` is :data:`True` and :attr:`buffered` is :data:`False`
the value of :attr:`buffer_size` defaults to 0 which means unbuffered,
in all other cases its value defaults to -1 which means to use the
system default buffer size.
"""
return 0 if self.async and not self.buffered else -1
return 0 if self.asynchronous and not self.buffered else -1

@mutable_property
def buffered(self):
"""
Control whether command output is buffered to temporary files.

When :attr:`async` is :data:`True` and the standard output and/or error
When :attr:`asynchronous` is :data:`True` and the standard output and/or error
streams are being captured, temporary files will be used to collect the
output. This enables the use of the :attr:`output`, :attr:`stdout` and
:attr:`stderr` properties to easily get the full output of the command
Expand Down Expand Up @@ -371,7 +371,7 @@ def buffered(self):
known_states = set(['BLANK', 'LOCK', 'UNBLANK'])

while True:
options = dict(async=True, capture=True, buffered=False)
options = dict(asynchronous=True, capture=True, buffered=False)
with execute('xscreensaver-command', '-watch', **options) as command:
for line in command:
tokens = line.split()
Expand Down Expand Up @@ -444,8 +444,8 @@ def check(self):

If this option is :data:`True` (the default) and the external command
exits with a nonzero status code :exc:`ExternalCommandFailed` will be
raised by :func:`start()` (when :attr:`async` isn't set) or
:func:`wait()` (when :attr:`async` is set).
raised by :func:`start()` (when :attr:`asynchronous` isn't set) or
:func:`wait()` (when :attr:`asynchronous` is set).
"""
return True

Expand Down Expand Up @@ -1373,7 +1373,7 @@ def start(self):

:raises: - :exc:`ExternalCommandFailed` when
:attr:`~ExternalCommand.check` is :data:`True`,
:attr:`async` is :data:`False` and the external command
:attr:`asynchronous` is :data:`False` and the external command
exits with a nonzero status code.

- :exc:`ValueError` when the external command is still
Expand All @@ -1383,12 +1383,12 @@ def start(self):

This method instantiates a :class:`subprocess.Popen` object based on
the defaults defined by :class:`ExternalCommand` and the overrides
configured by the caller. What happens then depends on :attr:`async`:
configured by the caller. What happens then depends on :attr:`asynchronous`:

- If :attr:`async` is set :func:`start()` starts the external command
- If :attr:`asynchronous` is set :func:`start()` starts the external command
but doesn't wait for it to end (use :func:`wait()` for that).

- If :attr:`async` isn't set the ``communicate()`` method on the
- If :attr:`asynchronous` isn't set the ``communicate()`` method on the
:attr:`subprocess` object is called to synchronously execute the
external command.
"""
Expand All @@ -1412,7 +1412,7 @@ def start(self):
kw['stdout'] = self.stdout_stream.prepare_output(self.stdout_file, self.capture)
kw['stderr'] = (subprocess.STDOUT if self.merge_streams else
self.stderr_stream.prepare_output(self.stderr_file, self.capture_stderr))
if self.retry and not self.async:
if self.retry and not self.asynchronous:
# Retry a failing synchronous command.
while True:
self.start_once(check=False, **kw)
Expand Down Expand Up @@ -1486,7 +1486,7 @@ def start_once(self, check=None, **kw):
# subprocess.Popen object without losing track of the process ID.
self.pid = self.subprocess.pid
# Synchronously wait for the external command to end?
if not self.async:
if not self.asynchronous:
self.logger.debug("Joining synchronous process using subprocess.Popen.communicate() ..")
stdout, stderr = self.subprocess.communicate(self.encoded_input)
self.stdout_stream.finalize(stdout)
Expand All @@ -1508,10 +1508,10 @@ def wait(self, check=None, **kw):
:param kw: Any keyword arguments are passed on to
:func:`~executor.process.ControllableProcess.wait_for_process()`.
:raises: :exc:`ExternalCommandFailed` when :attr:`check` is
:data:`True`, :attr:`async` is :data:`True` and the external
:data:`True`, :attr:`asynchronous` is :data:`True` and the external
command exits with a nonzero status code.

The :func:`wait()` function is only useful when :attr:`async` is
The :func:`wait()` function is only useful when :attr:`asynchronous` is
:data:`True`, it performs the following steps:

1. If :attr:`was_started` is :data:`False` the :func:`start()` method
Expand Down Expand Up @@ -1571,7 +1571,7 @@ def load_output(self):
Load output captured from the standard output/error streams.

Reads the contents of the temporary file(s) created by :func:`start()`
(when :attr:`async` and :attr:`capture` are both set) into memory so
(when :attr:`asynchronous` and :attr:`capture` are both set) into memory so
that the output doesn't get lost when the temporary file is cleaned up
by :func:`cleanup()`.
"""
Expand All @@ -1587,7 +1587,7 @@ def cleanup(self):

- The temporary file(s) used to to buffer the external command's
:attr:`input`, :attr:`stdout` and :attr:`stderr` (only when
:attr:`async` is :data:`True`).
:attr:`asynchronous` is :data:`True`).

- File handles to the previously mentioned temporary files and
:data:`os.devnull` (used to implement the :attr:`silent` option).
Expand All @@ -1603,7 +1603,7 @@ def cleanup(self):
self.stderr_stream.finalize()
# Prepare to garbage collect the subprocess.Popen object?
if self.subprocess is not None:
if self.async:
if self.asynchronous:
self.logger.debug("Joining asynchronous process using subprocess.Popen.wait() ..")
# Perform a wait to allow the system to release the resources
# associated with the child process; if a wait is not performed,
Expand Down Expand Up @@ -1680,15 +1680,15 @@ def __enter__(self):
:keyword:`with` statement, the command is automatically started when
entering the context and terminated when leaving the context.

If the proces hasn't already been started yet :attr:`async` is
If the proces hasn't already been started yet :attr:`asynchronous` is
automatically set to :data:`True` (if it's not already :data:`True`),
otherwise the command will have finished execution by the time the body
of the :keyword:`with` statement is executed (which isn't really all
that useful :-).
"""
if not self.was_started:
if not self.async:
self.async = True
if not self.asynchronous:
self.asynchronous = True
self.start()
return self

Expand Down Expand Up @@ -1746,7 +1746,7 @@ def __iter__(self):
"""
if not self.was_started:
if not self.buffered:
self.async = True
self.asynchronous = True
self.start()
for is_enabled, value_property in (('capture', 'stdout'), ('capture_stderr', 'stderr')):
if getattr(self, is_enabled):
Expand Down Expand Up @@ -1811,7 +1811,7 @@ def prepare_input(self):
:class:`subprocess.Popen` as the ``stdin`` argument.
"""
if self.command.input is not None:
if self.command.async and self.command.input is not True:
if self.command.asynchronous and self.command.input is not True:
# Store the input provided by the caller in a temporary file
# and connect the file to the command's standard input stream.
self.prepare_temporary_file()
Expand Down Expand Up @@ -1846,7 +1846,7 @@ def prepare_output(self, file, capture):
self.redirect(file)
return self.fd
elif capture or (self.command.silent and not self.command.really_silent):
if self.command.async and self.command.buffered:
if self.command.asynchronous and self.command.buffered:
# Capture the stream to a temporary file.
self.prepare_temporary_file()
return self.fd
Expand Down
2 changes: 1 addition & 1 deletion executor/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def run_command(arguments, timeout=None):
"""
timer = Timer()
logger.info("Running command: %s", quote(arguments))
with execute(*arguments, async=True) as command:
with execute(*arguments, asynchronous=True) as command:
# Wait for the command to finish or exceed the given timeout.
while command.is_running:
if timeout and timer.elapsed_time > timeout:
Expand Down
6 changes: 3 additions & 3 deletions executor/concurrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def add(self, command, identifier=None, log_file=None):
When a command is added to a command pool the following options are
changed automatically:

- The :attr:`~executor.ExternalCommand.async` property is set to
- The :attr:`~executor.ExternalCommand.asynchronous` property is set to
:data:`True`. If you want the commands to execute with a concurrency
of one then you should set :attr:`concurrency` to one.

Expand All @@ -217,8 +217,8 @@ def add(self, command, identifier=None, log_file=None):
user tries to answer one of the prompts it will be impossible to tell
which of the subprocesses will receive the user's reply).
"""
# Configure the command to run asynchronously.
command.async = True
# Configure the command to run asynchronoushronously.
command.asynchronous = True
# Configure the command to run without a controlling terminal?
if self.concurrency > 1:
command.tty = False
Expand Down
2 changes: 1 addition & 1 deletion executor/ssh/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ class SecureTunnel(RemoteCommand):
"""

@mutable_property
def async(self):
def asynchronous(self):
"""Whether to enable asynchronous command execution (a boolean, defaults to :data:`True`)."""
return True

Expand Down
4 changes: 2 additions & 2 deletions executor/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ class EphemeralTCPServer(ExternalCommand, EphemeralPortAllocator):
"""

@property
def async(self):
"""Ephemeral TCP servers always set :attr:`.ExternalCommand.async` to :data:`True`."""
def asynchronous(self):
"""Ephemeral TCP servers always set :attr:`.ExternalCommand.asynchronous` to :data:`True`."""
return True

def start(self, **options):
Expand Down
40 changes: 20 additions & 20 deletions executor/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ def test_status_code_checking(self):
self.assertEqual(e.returncode, 42)
self.assertTrue('whatever' in e.error_message)
# Make sure the CommandNotFound exception is raised consistently
# regardless of the values of the `shell' and `async' options.
for async in True, False:
# regardless of the values of the `shell' and `asynchronous' options.
for asynchronous in True, False:
for shell in True, False:
cmd = ExternalCommand(MISSING_COMMAND, async=async, shell=shell)
cmd = ExternalCommand(MISSING_COMMAND, asynchronous=asynchronous, shell=shell)
self.assertRaises(CommandNotFound, cmd.wait)
assert cmd.returncode == COMMAND_NOT_FOUND_STATUS

Expand Down Expand Up @@ -350,7 +350,7 @@ def test_asynchronous_stream_to_file(self):
fd, filename = tempfile.mkstemp(prefix='executor-', suffix='-streaming.txt')
with open(filename, 'w') as handle:
cmd = ExternalCommand('for ((i=0; i<25; i++)); do echo $i; sleep 0.1; done',
async=True, stdout_file=handle)
asynchronous=True, stdout_file=handle)
cmd.start()

def expect_some_output():
Expand All @@ -376,7 +376,7 @@ def test_asynchronous_unbuffered_output(self):
'sys.stdout.write(sys.stdin.readline().upper())',
'sys.stdout.flush()',
'sys.stdout.write(sys.stdin.readline().upper())'),
async=True, buffered=False, capture=True, input=True
asynchronous=True, buffered=False, capture=True, input=True
)
with cmd:
# Message the command.
Expand Down Expand Up @@ -521,9 +521,9 @@ def test_environment_variable_handling(self):
cmd.wait()
assert cmd.output == 'Also works fine'

def test_simple_async_cmd(self):
def test_simple_asynchronous_cmd(self):
"""Make sure commands can be executed asynchronously."""
cmd = ExternalCommand('sleep 4', async=True)
cmd = ExternalCommand('sleep 4', asynchronous=True)
# Make sure we're starting from a sane state.
assert not cmd.was_started
assert not cmd.is_running
Expand Down Expand Up @@ -552,11 +552,11 @@ def assert_running():
assert cmd.is_finished
assert cmd.returncode == 0

def test_async_with_input(self):
def test_asynchronous_with_input(self):
"""Make sure asynchronous commands can be provided standard input."""
random_file = os.path.join(tempfile.gettempdir(), 'executor-%s-async-input-test' % os.getpid())
random_file = os.path.join(tempfile.gettempdir(), 'executor-%s-asynchronous-input-test' % os.getpid())
random_value = str(random.random())
cmd = ExternalCommand('cat > %s' % quote(random_file), async=True, input=random_value)
cmd = ExternalCommand('cat > %s' % quote(random_file), asynchronous=True, input=random_value)
try:
cmd.start()
cmd.wait()
Expand All @@ -568,10 +568,10 @@ def test_async_with_input(self):
if os.path.isfile(random_file):
os.unlink(random_file)

def test_async_with_output(self):
def test_asynchronous_with_output(self):
"""Make sure asynchronous command output can be captured."""
random_value = str(random.random())
cmd = ExternalCommand('echo %s' % quote(random_value), async=True, capture=True)
cmd = ExternalCommand('echo %s' % quote(random_value), asynchronous=True, capture=True)
cmd.start()
cmd.wait()
assert cmd.output == random_value
Expand All @@ -587,11 +587,11 @@ def coerce_timestamp(self, cmd):

def test_event_callbacks(self):
"""Make sure the ``start_event`` and ``finish_event`` callbacks are actually invoked."""
for async in True, False:
for asynchronous in True, False:
results = []
cmd = ExternalCommand(
'sleep', '0.1',
async=async,
asynchronous=asynchronous,
start_event=lambda cmd: results.append(('started', time.time())),
finish_event=lambda cmd: results.append(('finished', time.time())),
)
Expand All @@ -606,14 +606,14 @@ def test_event_callbacks(self):
def test_repr(self):
"""Make sure that repr() on external commands gives sane output."""
cmd = ExternalCommand('echo 42',
async=True,
asynchronous=True,
capture=True,
directory='/',
environment={'my_environment_variable': '42'})
assert repr(cmd).startswith('ExternalCommand(')
assert repr(cmd).endswith(')')
assert 'echo 42' in repr(cmd)
assert 'async=True' in repr(cmd)
assert 'asynchronous=True' in repr(cmd)
assert ('directory=%r' % '/') in repr(cmd)
assert 'my_environment_variable' in repr(cmd)
assert 'was_started=False' in repr(cmd)
Expand Down Expand Up @@ -707,19 +707,19 @@ def test_command_pool_retry(self):
# it exactly once. We expect this command to have succeeded when
# the command pool is finished.
script_1 = self.create_retry_script(directory, 2)
command_1 = ExternalCommand(script_1, async=True, retry=True, retry_limit=1)
command_1 = ExternalCommand(script_1, asynchronous=True, retry=True, retry_limit=1)
pool.add(command_1)
# Create a shell script that succeeds on the fourth run and retry
# it up to two times. We expect this command to have failed when
# the command pool is finished.
script_2 = self.create_retry_script(directory, 4)
command_2 = ExternalCommand(script_2, async=True, retry=True, retry_limit=2)
command_2 = ExternalCommand(script_2, asynchronous=True, retry=True, retry_limit=2)
pool.add(command_2)
# Include a command without retries that succeeds.
command_3 = ExternalCommand('true', async=True, retry=False)
command_3 = ExternalCommand('true', asynchronous=True, retry=False)
pool.add(command_3)
# Include a command without retries that fails.
command_4 = ExternalCommand('false', async=True, retry=False)
command_4 = ExternalCommand('false', asynchronous=True, retry=False)
pool.add(command_4)
# Run the commands in the pool, expecting an `CommandPoolFailed'
# exception because the second command will fail despite retrying
Expand Down