Skip to content
Merged
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
4 changes: 2 additions & 2 deletions docs/how-to/migrate-from-pytest-operator.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ def test_active(juju: jubilant.Juju, app: str):

However, instead of calling `status` directly, it's usually better to wait for a certain condition to be true. In python-libjuju you used `model.wait_for_idle`; in Jubilant you use [`juju.wait`](jubilant.Juju.wait), which has a simpler and more consistent API.

The `wait` method takes a *ready* callable, which takes a [`Status`](jubilant.Status) object. Internally, `wait` polls `juju status` every second and calls the *ready* callable, which must return True three times in a row (this is configurable).
The `wait` method takes a *ready* callable, which takes a [`Status`](jubilant.Status) object. Internally, `wait` polls `juju status` every second and calls the *ready* callable, which must return `True` three times in a row (this is configurable).

You can optionally provide an *error* callable, which also takes a `Status` object. If the *error* callable returns True, `wait` raises a [`WaitError`](jubilant.WaitError) immediately.
You can optionally provide an *error* callable, which also takes a `Status` object. If the *error* callable returns `True`, `wait` raises a [`WaitError`](jubilant.WaitError) immediately.

Jubilant provides helper functions to use for the *ready* and *error* callables, such as [`jubilant.all_active`](jubilant.all_active) and [`jubilant.any_error`](jubilant.any_error). These check whether the workload status of all (or any) applications and their units are in a given state.

Expand Down
12 changes: 6 additions & 6 deletions jubilant/_all_any.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def all_active(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only these applications (and their units) are tested. If an app is not
present in ``status.apps``, returns False.
present in ``status.apps``, returns ``False``.
"""
return _all_statuses_are('active', status, apps)

Expand All @@ -32,7 +32,7 @@ def all_blocked(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only these applications (and their units) are tested. If an app is not
present in ``status.apps``, returns False.
present in ``status.apps``, returns ``False``.
"""
return _all_statuses_are('blocked', status, apps)

Expand All @@ -45,7 +45,7 @@ def all_error(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only these applications (and their units) are tested. If an app is not
present in ``status.apps``, returns False.
present in ``status.apps``, returns ``False``.
"""
return _all_statuses_are('error', status, apps)

Expand All @@ -58,7 +58,7 @@ def all_maintenance(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only these applications (and their units) are tested. If an app is not
present in ``status.apps``, returns False.
present in ``status.apps``, returns ``False``.
"""
return _all_statuses_are('maintenance', status, apps)

Expand All @@ -71,7 +71,7 @@ def all_waiting(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only these applications (and their units) are tested. If an app is not
present in ``status.apps``, returns False.
present in ``status.apps``, returns ``False``.
"""
return _all_statuses_are('waiting', status, apps)

Expand Down Expand Up @@ -162,7 +162,7 @@ def all_agents_idle(status: Status, *apps: str) -> bool:
Args:
status: The status object being tested.
apps: If provided, only the unit agents of units from these applications are tested.
If an app is not present in ``status.apps``, returns False.
If an app is not present in ``status.apps``, returns ``False``.
"""
return _all_agent_statuses_are('idle', status, apps)

Expand Down
42 changes: 21 additions & 21 deletions jubilant/_juju.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def __str__(self) -> str:


class WaitError(Exception):
"""Raised when :meth:`Juju.wait`'s *error* callable returns True."""
"""Raised when :meth:`Juju.wait`'s *error* callable returns ``True``."""


ConfigValue = Union[bool, int, float, str, SecretURI]
Expand Down Expand Up @@ -142,14 +142,14 @@ def add_credential(
cloud: Name of the cloud to add credentials for.
credential: Path to a YAML file containing credential to add, or a mapping
representing the parsed credential YAML (``{'credentials': ...}``).
client: Set to True to save credentials on the client, meaning controllers
client: Set to true to save credentials on the client, meaning controllers
created later will have access to them. You must specify ``client=True``
or provide *controller* (or both).
controller: If specified, save credentials to the named controller.
region: Cloud region that the credential is valid for.
"""
if not client and controller is None:
raise TypeError('"client" must be True or "controller" must be specified (or both)')
raise TypeError('"client" must be true or "controller" must be specified (or both)')

args = ['add-credential', cloud]

Expand Down Expand Up @@ -330,7 +330,7 @@ def bootstrap(
workload machines in the model, exactly as if the constraints were set with
``juju set-model-constraints``.
credential: Name of cloud credential to use when bootstrapping.
force: If True, allow bypassing of checks such as supported bases.
force: If true, allow bypassing of checks such as supported bases.
model_defaults: Configuration options to set for all models.
storage_pool: Options for an initial storage pool as key-value pairs. ``name``
and ``type`` are required, plus any additional attributes.
Expand Down Expand Up @@ -438,7 +438,7 @@ def config(
Args:
app: Application name to get or set config for.
values: Mapping of config names to values to set.
app_config: When getting config, set this to True to get the
app_config: When getting config, set this to true to get the
(poorly-named) "application-config" values instead of charm config.
reset: Key or list of keys to reset to their defaults.
"""
Expand Down Expand Up @@ -637,11 +637,11 @@ def destroy_model(

Args:
model: Name of model to destroy.
destroy_storage: If True, destroy all storage instances in the model.
force: If True, force model destruction and ignore any errors.
no_wait: If True, rush through model destruction without waiting for each step
destroy_storage: If true, destroy all storage instances in the model.
force: If true, force model destruction and ignore any errors.
no_wait: If true, rush through model destruction without waiting for each step
to complete.
release_storage: If True, release all storage instances in the model.
release_storage: If true, release all storage instances in the model.
This is mutually exclusive with *destroy_storage*.
timeout: Maximum time (in seconds) to wait for each step in the model destruction.
This option can only be used with *force*.
Expand Down Expand Up @@ -949,7 +949,7 @@ def remove_application(

Args:
app: Name of the application or applications to remove.
destroy_storage: If True, also destroy storage attached to application units.
destroy_storage: If true, also destroy storage attached to application units.
force: Force removal even if an application is in an error state.
"""
args = ['remove-application', '--no-prompt', *app]
Expand Down Expand Up @@ -1027,7 +1027,7 @@ def remove_unit(
On Kubernetes models, this is actually the application name (a single string),
as individual units are not named; you must use *num_units* to remove more than
one unit on a Kubernetes model.
destroy_storage: If True, also destroy storage attached to units.
destroy_storage: If true, also destroy storage attached to units.
force: Force removal even if a unit is in an error state.
num_units: Number of units to remove (Kubernetes models only).
"""
Expand Down Expand Up @@ -1138,7 +1138,7 @@ def scp(
source: Source of file, in format ``[[<user>@]<target>:]<path>``.
destination: Destination for file, in format ``[<user>@]<target>[:<path>]``.
container: Name of container for Kubernetes charms. Defaults to the charm container.
host_key_checks: Set to False to disable host key checking (insecure).
host_key_checks: Set to false to disable host key checking (insecure).
scp_options: ``scp`` client options, for example ``['-r', '-C']``.
"""
# Need this check because str is also an iterable of str.
Expand Down Expand Up @@ -1297,7 +1297,7 @@ def ssh(
``juju.ssh('mysql/0', 'echo foo', ...)``.
args: Arguments of the command.
container: Name of container for Kubernetes charms. Defaults to the charm container.
host_key_checks: Set to False to disable host key checking (insecure).
host_key_checks: Set to false to disable host key checking (insecure).
ssh_options: OpenSSH client options, for example ``['-i', '/path/to/private.key']``.
user: User account to make connection with. Defaults to ``ubuntu`` account.
"""
Expand Down Expand Up @@ -1333,7 +1333,7 @@ def trust(

Args:
app: Application name to set trust status for.
remove: Set to True to remove trust status.
remove: Set to true to remove trust status.
scope: On Kubernetes models, this must be set to "cluster", as the trust operation
grants the charm full access to the cluster.
"""
Expand Down Expand Up @@ -1393,10 +1393,10 @@ def wait(
timeout: float | None = None,
successes: int = 3,
) -> Status:
"""Wait until ``ready(status)`` returns true.
"""Wait until ``ready(status)`` returns ``True``.

This fetches the Juju status repeatedly (waiting *delay* seconds between each call),
and returns the last status after the *ready* callable returns true for *successes*
and returns the last status after the *ready* callable returns ``True`` for *successes*
times in a row.

Example::
Expand All @@ -1422,21 +1422,21 @@ def wait(
logging.getLogger('jubilant.wait').setLevel('WARNING')

Args:
ready: Callable that takes a :class:`Status` object and returns true when the wait
should be considered ready. It needs to return true *successes* times in a row
ready: Callable that takes a :class:`Status` object and returns ``True`` when the wait
should be considered ready. It needs to return ``True`` *successes* times in a row
before ``wait`` returns.
error: Callable that takes a :class:`Status` object and returns true when ``wait``
error: Callable that takes a :class:`Status` object and returns ``True`` when ``wait``
should raise an error (:class:`WaitError`).
delay: Delay in seconds between status calls.
timeout: Overall timeout in seconds; :class:`TimeoutError` is raised if this
is reached. If not specified, uses the *wait_timeout* specified when the
instance was created.
successes: Number of times *ready* must return true for the wait to succeed.
successes: Number of times *ready* must return ``True`` for the wait to succeed.

Raises:
TimeoutError: If the *timeout* is reached. A string representation
of the last status, if any, is added as an exception note.
WaitError: If the *error* callable returns True. A string representation
WaitError: If the *error* callable returns ``True``. A string representation
of the last status is added as an exception note.
"""
if timeout is None:
Expand Down