Juju CLI wrapper, primarily for charm integration testing
Project description
Jubilant, the joyful library for driving Juju
Jubilant is a Python library that wraps the Juju CLI, primarily for use in charm integration tests. It provides methods that map 1:1 to Juju CLI commands, but with a type-annotated, Pythonic interface.
You should consider switching to Jubilant if your integration tests currently use pytest-operator (and they probably do). Jubilant has an API you'll pick up quickly, and it avoids some of the pain points of python-libjuju, such as websocket failures and having to use async. Read our design goals.
Jubilant 1.0.0 was released in April 2025. We'll avoid making breaking changes to the API after this point.
Using Jubilant
Jubilant is published to PyPI, so you can install and use it with your favorite Python package manager:
$ pip install jubilant
# or
$ uv add jubilant
Because Jubilant calls the Juju CLI, you'll also need to install Juju.
To use Jubilant in Python code:
import jubilant
juju = jubilant.Juju()
juju.deploy('snappass-test')
juju.wait(jubilant.all_active)
# Or only wait for specific applications:
juju.wait(lambda status: jubilant.all_active(status, 'snappass-test', 'another-app'))
Below is an example of a charm integration test. First we define a module-scoped pytest fixture named juju which creates a temporary model and runs the test with a Juju instance pointing at that model. Jubilant'stemp_model context manager creates the model during test setup and destroys it during teardown:
# conftest.py
@pytest.fixture(scope='module')
def juju():
with jubilant.temp_model() as juju:
yield juju
# test_deploy.py
def test_deploy(juju: jubilant.Juju): # Use the "juju" fixture
juju.deploy('snappass-test') # Deploy the charm
status = juju.wait(jubilant.all_active) # Wait till the app and unit are 'active'
# Hit the Snappass HTTP endpoint to ensure it's up and running.
address = status.apps['snappass-test'].units['snappass-test/0'].address
response = requests.get(f'http://{address}:5000/', timeout=10)
response.raise_for_status()
assert 'snappass' in response.text.lower()
You don't have to use pytest with Jubilant, but it's what we recommend. Pytest's assert-based approach is a straight-forward way to write tests, and its fixtures are helpful for structuring setup and teardown.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jubilant-1.11.0.tar.gz.
File metadata
- Download URL: jubilant-1.11.0.tar.gz
- Upload date:
- Size: 34.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69d13d2a0c9604a146fb7172732b9344f7aa14a35cdc29a37189831a724dc80a
|
|
| MD5 |
0a581b6eba15e394ba57322c99007ac3
|
|
| BLAKE2b-256 |
1c0a4112c6a16440efa7047b58ea7cd3751a75ef4b73e75fa4b4b4aadf7cbf1c
|
Provenance
The following attestation bundles were made for jubilant-1.11.0.tar.gz:
Publisher:
publish.yaml on canonical/jubilant
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jubilant-1.11.0.tar.gz -
Subject digest:
69d13d2a0c9604a146fb7172732b9344f7aa14a35cdc29a37189831a724dc80a - Sigstore transparency entry: 2004047575
- Sigstore integration time:
-
Permalink:
canonical/jubilant@118268b1b2dfc1c0983038cee5cc202752b778cc -
Branch / Tag:
refs/tags/v1.11.0 - Owner: https://github.com/canonical
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@118268b1b2dfc1c0983038cee5cc202752b778cc -
Trigger Event:
push
-
Statement type:
File details
Details for the file jubilant-1.11.0-py3-none-any.whl.
File metadata
- Download URL: jubilant-1.11.0-py3-none-any.whl
- Upload date:
- Size: 36.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
900427d616c75f1cfb6ee11212fefe9c7877111209630a87b2b2556a37d626e7
|
|
| MD5 |
03535a34153fb9e3021a7a52698a00c1
|
|
| BLAKE2b-256 |
63728ba367bc63f03b9f0a31c7975fec8e7f3c9da3516a8d1db668164fc1801b
|
Provenance
The following attestation bundles were made for jubilant-1.11.0-py3-none-any.whl:
Publisher:
publish.yaml on canonical/jubilant
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jubilant-1.11.0-py3-none-any.whl -
Subject digest:
900427d616c75f1cfb6ee11212fefe9c7877111209630a87b2b2556a37d626e7 - Sigstore transparency entry: 2004047669
- Sigstore integration time:
-
Permalink:
canonical/jubilant@118268b1b2dfc1c0983038cee5cc202752b778cc -
Branch / Tag:
refs/tags/v1.11.0 - Owner: https://github.com/canonical
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@118268b1b2dfc1c0983038cee5cc202752b778cc -
Trigger Event:
push
-
Statement type: