{"library":"ops","title":"Juju Ops Framework","description":"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.","language":"python","status":"active","last_verified":"Sun May 17","install":{"commands":["pip install ops","pip install ops[testing]"],"cli":null},"imports":["from ops.charm import CharmBase","from ops.framework import Framework","from ops.framework import StoredState","from ops.main import main","from ops.pebble import Container","from ops.pebble import PebbleClient","from ops.testing import Context","from ops.model import ActiveStatus","from ops.model import BlockedStatus"],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"import ops\nfrom ops.charm import CharmBase\nfrom ops.framework import StoredState\n\n\nclass MyCharm(CharmBase):\n    _stored = StoredState()\n\n    def __init__(self, framework: ops.Framework):\n        super().__init__(framework)\n        self.framework.observe(self.on.install, self._on_install)\n        self.framework.observe(self.on.config_changed, self._on_config_changed)\n        self._stored.set_default(initialized=False)\n\n    def _on_install(self, event: ops.InstallEvent):\n        # Example: Set initial status and workload version\n        self.unit.status = ops.BlockedStatus(\"Waiting for configuration\")\n        self.unit.set_workload_version(\"v1.0.0\")\n        self._stored.initialized = True\n        self.logger.info(\"Charm installed.\")\n\n    def _on_config_changed(self, event: ops.ConfigChangedEvent):\n        # Example: Update status after configuration change\n        if self._stored.initialized:\n            self.unit.status = ops.ActiveStatus(\"Ready\")\n            self.logger.info(\"Configuration changed and charm is active.\")\n\n\nif __name__ == \"__main__\":\n    # The main entry point for a Juju charm\n    ops.main(MyCharm)","lang":"python","description":"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.","tag":null,"tag_description":null,"last_tested":null,"results":[]},"compatibility":{"tag":null,"tag_description":null,"last_tested":"2026-05-17","installed_version":"2.23.2","pypi_latest":"3.7.0","is_stale":true,"summary":{"python_range":"3.10–3.9","success_rate":100,"avg_install_s":2.2,"avg_import_s":0.55,"wheel_type":"wheel"},"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.44,"mem_mb":12.8,"disk_size":"23.4M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.44,"mem_mb":12.8,"disk_size":"23.9M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.2,"import_time_s":0.31,"mem_mb":12.8,"disk_size":"25M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.3,"import_time_s":0.3,"mem_mb":12.8,"disk_size":"25M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.77,"mem_mb":14.2,"disk_size":"26.1M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.8,"mem_mb":14.2,"disk_size":"26.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.3,"import_time_s":0.73,"mem_mb":14.2,"disk_size":"27M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.3,"import_time_s":0.69,"mem_mb":14.2,"disk_size":"28M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.68,"mem_mb":14.3,"disk_size":"17.9M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.62,"mem_mb":14.3,"disk_size":"18.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2,"import_time_s":0.64,"mem_mb":14.3,"disk_size":"19M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.1,"import_time_s":0.65,"mem_mb":14.3,"disk_size":"20M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.59,"mem_mb":15.3,"disk_size":"17.6M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.59,"mem_mb":15.3,"disk_size":"18.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2,"import_time_s":0.61,"mem_mb":15.3,"disk_size":"19M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2,"import_time_s":0.6,"mem_mb":15.3,"disk_size":"19M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.4,"mem_mb":12.5,"disk_size":"22.8M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.38,"mem_mb":12.5,"disk_size":"23.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"ops","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.6,"import_time_s":0.36,"mem_mb":12.5,"disk_size":"24M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"testing","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.5,"import_time_s":0.35,"mem_mb":12.5,"disk_size":"24M"}]}}