Ops is the official Python library for writing Juju charms, enabling developers to build robust and reactive operators for cloud-native applications. It provides high-level abstractions for interacting with Juju, handling lifecycle events, managing application status, and interacting with container workloads via Pebble. The library is actively maintained, with frequent releases addressing bug fixes, performance improvements, and compatibility with the latest Juju versions, typically every few weeks.
pip install opsVerified import paths — ran on the pinned version, not inferred.
This minimal example demonstrates a basic Juju charm that handles `install` and `config_changed` events. It sets the unit's status and workload version, and uses `StoredState` to persist simple charm data across hooks. The `ops.main()` function is essential for running the charm in the Juju environment.
To maintain compatibility with older Juju environments or to avoid unexpected changes, explicitly set the desired Juju version in your `ops.testing.Context` constructor: `Context(charm_type, juju_version='2.9.x')`.
If your tests or error handling relied on extracting the full command from `PebbleExecError` messages, you'll need to adjust your parsing logic. Ensure sensitive command arguments are not the first item if they are crucial for debugging failure context.
To simplify debugging and allow direct assertion of original exception types, set the environment variable `SCENARIO_BARE_CHARM_ERRORS=true` when running your tests. This will disable the `UncaughtCharmError` wrapping.
For typical charm development, prefer using the higher-level abstractions provided by the main `ops` library (e.g., `CharmBase`, `PebbleClient`, `Relation` objects). Only use `ops.hookcmds` if you specifically require direct Juju command access for advanced framework development or specific niche scenarios.
Ensure 'ops' is listed in your charm's `requirements.txt` file and `charmcraft pack` is used to build the charm, which handles packaging dependencies. For development or testing, make sure 'ops' is installed in your active Python environment or add the charm's 'lib' and 'venv' directories to `PYTHONPATH`.
Review the `ops` charm code, specifically around `ops.model` interactions, to ensure all mandatory 'name' parameters are supplied when defining or operating on Juju entities. For example, when creating a secret, ensure the secret name is passed.
Debug the code to inspect the type and value of the object ('X') before the attribute access (e.g., `print(type(self.model.unit))`, `print(event.relation)`). Ensure the object is properly initialized and available in the current scope, and add checks for `None` or appropriate conditionals if the object's presence is not guaranteed. Also, double-check for typos in attribute names.Examine the `juju debug-log` output for the specific unit to find the message provided by the charm that explains why `BlockedStatus` was set. Then, address the underlying cause, which could involve providing necessary configuration, establishing required relations, or resolving an internal application issue as indicated by the charm's status message.