Minor improvements
authorCory Johns <johnsca@gmail.com>
Fri, 9 Dec 2016 21:56:28 +0000 (16:56 -0500)
committerCory Johns <johnsca@gmail.com>
Wed, 14 Dec 2016 17:47:49 +0000 (12:47 -0500)
* Sleep a small amount in block_until to avoid CPU-heavy busy-wait
* Better repr of ModelEntities for debugging
* Better errors when statuses accessed on dead units and applications

juju/application.py
juju/model.py
juju/unit.py

index 74f9057..69f412f 100644 (file)
@@ -41,14 +41,14 @@ class Application(model.ModelEntity):
         """Get the application status, as set by the charm's leader.
 
         """
-        return self.data['status']['current']
+        return self.safe_data['status']['current']
 
     @property
     def status_message(self):
         """Get the application status message, as set by the charm's leader.
 
         """
-        return self.data['status']['message']
+        return self.safe_data['status']['message']
 
     @property
     def tag(self):
index 621ae06..7897d42 100644 (file)
@@ -207,18 +207,16 @@ class ModelEntity(object):
         self.connected = connected
         self.connection = model.connection
 
+    def __repr__(self):
+        return '<{} entity_id="{}">'.format(type(self).__name__,
+                                            self.entity_id)
+
     def __getattr__(self, name):
         """Fetch object attributes from the underlying data dict held in the
         model.
 
         """
-        if self.data is None:
-            raise DeadEntityException(
-                "Entity {}:{} is dead - its attributes can no longer be "
-                "accessed. Use the .previous() method on this object to get "
-                "a copy of the object at its previous state.".format(
-                    self.entity_type, self.entity_id))
-        return self.data[name]
+        return self.safe_data[name]
 
     def __bool__(self):
         return bool(self.data)
@@ -285,6 +283,22 @@ class ModelEntity(object):
         return self.model.state.entity_data(
             self.entity_type, self.entity_id, self._history_index)
 
+    @property
+    def safe_data(self):
+        """The data dictionary for this entity.
+
+        If this `ModelEntity` points to the dead state, it will
+        raise `DeadEntityException`.
+
+        """
+        if self.data is None:
+            raise DeadEntityException(
+                "Entity {}:{} is dead - its attributes can no longer be "
+                "accessed. Use the .previous() method on this object to get "
+                "a copy of the object at its previous state.".format(
+                    self.entity_type, self.entity_id))
+        return self.data
+
     def previous(self):
         """Return a copy of this object as was at its previous state in
         history.
@@ -425,13 +439,13 @@ class Model(object):
             lambda: len(self.machines) == 0
         )
 
-    async def block_until(self, *conditions, timeout=None):
+    async def block_until(self, *conditions, timeout=None, wait_period=0.5):
         """Return only after all conditions are true.
 
         """
         async def _block():
             while not all(c() for c in conditions):
-                await asyncio.sleep(0)
+                await asyncio.sleep(wait_period)
         await asyncio.wait_for(_block(), timeout)
 
     @property
index dc5fa63..ab9d1d0 100644 (file)
@@ -14,42 +14,42 @@ class Unit(model.ModelEntity):
         """Returns the current agent status string.
 
         """
-        return self.data['agent-status']['current']
+        return self.safe_data['agent-status']['current']
 
     @property
     def agent_status_since(self):
         """Get the time when the `agent_status` was last updated.
 
         """
-        return parse_date(self.data['agent-status']['since'])
+        return parse_date(self.safe_data['agent-status']['since'])
 
     @property
     def agent_status_message(self):
         """Get the agent status message.
 
         """
-        return self.data['agent-status']['message']
+        return self.safe_data['agent-status']['message']
 
     @property
     def workload_status(self):
         """Returns the current workload status string.
 
         """
-        return self.data['workload-status']['current']
+        return self.safe_data['workload-status']['current']
 
     @property
     def workload_status_since(self):
         """Get the time when the `workload_status` was last updated.
 
         """
-        return parse_date(self.data['workload-status']['since'])
+        return parse_date(self.safe_data['workload-status']['since'])
 
     @property
     def workload_status_message(self):
         """Get the workload status message.
 
         """
-        return self.data['workload-status']['message']
+        return self.safe_data['workload-status']['message']
 
     @property
     def tag(self):
@@ -237,8 +237,8 @@ class Unit(model.ModelEntity):
         if not status.applications[app]['units'].get(self.name):
             return False
 
-        return status.applications[app]['units'][self.name].get('leader', False)
-
+        return status.applications[app]['units'][self.name].get('leader',
+                                                                False)
 
     async def get_metrics(self):
         metrics = await self.model.get_metrics(self.tag)