Registry / testing / jubilant

jubilant

JSON →
library1.10.0pypypi✓ verified 85d ago

Jubilant is a Python library that provides a high-level, asynchronous wrapper around the Juju CLI, primarily designed for integration testing of Juju charms. It simplifies programmatic interactions with Juju controllers and models, allowing for automation of deployments, configurations, and status checks. The library is actively maintained by Canonical, with frequent minor releases, and is currently at version 1.8.0.

pip install jubilant
INSTALL
IMPORT
SIG · JUBILANT
J
jubilant
testingpythonv1.10.0
Install
1.8s avg
Import
365ms
Disk
19MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v1.9.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.379s · 20.2MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 1.8s · import 0.350s · 21MB
19MB installed
● package 19MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Juju
from jubilant import Juju
The primary class for interacting with the Juju CLI and its commands.
jubilant_backports
import jubilant_backports as jubilant
Use this import pattern if you installed 'jubilant-backports' for Juju 2.9 compatibility, allowing you to use the API as if it were the standard 'jubilant' package.

This quickstart demonstrates how to initialize the `Juju` client, add a temporary Juju model, deploy a charm, wait for its status, and then destroy the model. This example is asynchronous and requires the 'juju' CLI to be installed and configured on your system. Using `Juju.temp_model()` as a context manager is generally preferred for testing scenarios to ensure cleanup.

import asyncio from jubilant import Juju async def main(): juju = Juju() model_name = "my-temp-test-model" print(f"Attempting to add Juju model: {model_name}") try: # Add a temporary model. For real tests, consider juju.temp_model() # which uses a context manager for automatic cleanup. await juju.add_model(model_name) print(f"Successfully added model '{model_name}'. Deploying charm...") # Deploy a simple charm await juju.deploy("ch:ubuntu", model=model_name) print("Ubuntu charm deployment initiated.") # Wait for the charm to be active await juju.wait_for_idle(apps=["ubuntu"], model=model_name) print("Ubuntu charm is active and idle.") status = await juju.get_status(model=model_name) print(f"Model '{model_name}' status: {status.model.status}") except Exception as e: print(f"An error occurred during Juju operations: {e}") finally: print(f"Attempting to destroy Juju model: {model_name}") await juju.destroy_model(model_name) print(f"Model '{model_name}' destroyed.") if __name__ == "__main__": # This example requires the Juju CLI to be installed and configured # on your system, and supports Python 3.8+. asyncio.run(main())
Debug
Known issues
breakingThe `Juju.offer()` method's API was updated in v1.8.0 to explicitly respect `self.model`. If your code previously relied on implicit model targeting behavior when calling `offer()`, it might now target a different model or require an explicit `model` argument to ensure the correct context.
fix
Review all calls to `Juju.offer()` in your codebase. Explicitly provide the `model` argument (e.g., `model=my_model_name`) if the offer needs to target a specific model that is not the default for the `Juju` instance.
affects: >=1.8.0
gotchaJubilant acts as a programmatic wrapper around the Juju command-line interface (CLI). For Jubilant to function, the `juju` CLI must be installed on your system and accessible via the system's PATH. This is an essential external dependency, not a Python package managed by pip.
fix
Install the Juju CLI (e.g., `snap install juju --classic` on Linux, or follow official Juju documentation for other platforms) and ensure its executable is in your system's PATH. You can verify the installation by running `juju --version` in your terminal.
affects: All versions
gotchaIf you need to interact with Juju 2.9 controllers, you must use the `jubilant-backports` package instead of the standard `jubilant` package. `jubilant-backports` is specifically designed for Juju 2.9 compatibility, while `jubilant` targets Juju 3.x+.
fix
Instead of `pip install jubilant`, use `pip install jubilant-backports`. In your Python code, change your imports from `from jubilant import Juju` to `import jubilant_backports as jubilant` (or `from jubilant_backports import Juju`) to maintain API compatibility.
affects: All versions (when targeting Juju 2.9)
gotchaIn v1.2.0, the `all_*` and `any_*` helper methods (e.g., `jubilant.all_active`) were updated to correctly include subordinate units in their evaluations. While considered a bug fix, this behavioral change might affect tests or logic that implicitly relied on subordinate units being excluded.
fix
Review any code utilizing `all_*` or `any_*` helpers. If your logic previously assumed these helpers would exclude subordinate units, you may need to adjust your expectations or filtering mechanisms.
affects: >=1.2.0
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'jubilant'
The 'jubilant' Python package has not been installed in your current Python environment.
fix
Open your terminal or command prompt and run `pip install jubilant` to install the library.
jubilant.errors.JujuError: Command 'juju' not found in PATH. Make sure Juju CLI is installed.
Jubilant could not find the 'juju' executable. This indicates the Juju CLI is either not installed or not configured correctly in your system's environment PATH.
fix
Install the Juju CLI according to the official Juju documentation for your operating system (e.g., `snap install juju --classic` on Linux), and ensure its installation directory is added to your system's PATH environment variable. Verify by running `juju --version` in a new terminal session.
juju status --format json: application 'my-app' not found (stderr: ) (exit code 1)
This error, originating from the underlying Juju CLI, usually means that an application, model, or other Juju resource specified in your Jubilant code does not exist, is misspelled, or is not in the expected state within the targeted Juju model.
fix
Carefully check the names of applications, models, and other Juju entities used in your Jubilant calls. Ensure they match your Juju environment exactly and that the Juju controller and model are in the expected operational state before the call is made.
SyntaxError: invalid syntax
Jubilant is built on Python's `asyncio` framework and uses `async/await` syntax. `asyncio.run()` also requires Python 3.7+. Jubilant itself requires Python 3.8+.
fix
Ensure you are running your Python code with Python 3.8 or a newer version to support the required syntax and `asyncio` features.
Upgrade
Version history
1.10.0latest on PyPI · released May 28, 2026
Audit
Dependencies

No dependency data recorded yet.

Agent activity
11 hits · last 30 days
node
8
Amazon
1
Resources
jubilant — pip install jubilant · libregistry