aboutsummaryrefslogtreecommitdiffstats
path: root/pushover.py
diff options
context:
space:
mode:
Diffstat (limited to 'pushover.py')
-rw-r--r--pushover.py94
1 files changed, 90 insertions, 4 deletions
diff --git a/pushover.py b/pushover.py
index ea54e44..45bfc9a 100644
--- a/pushover.py
+++ b/pushover.py
@@ -1,9 +1,24 @@
-#| /usr/bin/python2
+""" This modules aims at being a comprehensive implementation of the Pushover
+API as described at https://pushover.net/api.
+
+After being imported, the module must be initialize by calling the :func:`init`
+function with a valid application token before sending messages.
+
+A typical use of the module looks like this::
+
+ import pushover
+
+ pushover.init("token")
+ client = Client("client-id")
+ client.send_message("Hello!", title="Hello", priority=1)
+"""
import requests
import time
-__all__ = ["init", "get_sounds", "Client", "InitError", "RequestError"]
+__all__ = ["init", "get_sounds", "Client", "MessageRequest",
+ "InitError", "RequestError"]
+
BASE_URL = "https://api.pushover.net/1/"
MESSAGE_URL = BASE_URL + "messages.json"
USER_URL = BASE_URL + "users/validate.json"
@@ -14,6 +29,12 @@ SOUNDS = None
TOKEN = None
def get_sounds():
+ """Fetch and return a list of sounds (as a list of strings) recognized by
+ Pushover and that can be used in a notification message.
+
+ The result is cached: a request is made to the Pushover server only
+ the first time this function is called.
+ """
global SOUNDS
if not SOUNDS:
request = Request("get", SOUND_URL, {})
@@ -21,17 +42,28 @@ def get_sounds():
return SOUNDS
def init(token, sound=False):
+ """Initialize the module by setting the application token which will be
+ used to send messages. If ``sound`` is ``True`` also returns the list of
+ valid sounds by calling the :func:`get_sounds` function.
+ """
global TOKEN
TOKEN = token
if sound:
return get_sounds()
class InitError(Exception):
+ """Exception which is raised when trying to send a message before
+ initializing the module.
+ """
def __str__(self):
return "Init the pushover module by calling the init function"
class RequestError(Exception):
+ """Exception which is raised when Pushover's API returns an error code.
+
+ The list of errors is stored in the :attr:`errors` attribute.
+ """
def __init__(self, errors):
Exception.__init__(self)
@@ -41,6 +73,10 @@ class RequestError(Exception):
return "\n==> " + "\n==> ".join(self.errors)
class Request:
+ """Base class to send a request to the Pushover server and check the return
+ status code. The request is sent on the instance initialization and raises
+ a :class:`RequestError` exception when the request is rejected.
+ """
def __init__(self, request_type, url, payload):
if not TOKEN:
@@ -56,18 +92,45 @@ class Request:
print self.answer
class MessageRequest(Request):
+ """Class representing a message request to the Pushover API. You do not
+ need to create them yourself, but the :func:`Client.send_message` function
+ returns :class:`MessageRequest` objects if you need to inspect the requests
+ after they have been answered by the Pushover server.
+
+ The :attr:`answer` attribute contains a JSON representation of the answer
+ made by the Pushover API. In the case where you have sent a message with
+ a priority of 2, you can poll the status of the notification with the
+ :func:`poll` function.
+ """
def __init__(self, payload):
Request.__init__(self, "post", MESSAGE_URL, payload)
self.receipt = None
if payload.get("priority", 0) == 2:
self.receipt = self.answer["receipt"]
- self.parameters = ["expired", "called_back", "expired"]
+ self.parameters = ["expired", "called_back", "acknowledged"]
for parameter in self.parameters:
setattr(self, parameter, False)
setattr(self, parameter + "_at", 0)
def poll(self):
+ """If the message request has a priority of 2, Pushover will keep
+ sending the same notification until the client acknowledges it. Calling
+ the :func:`poll` function will update the status of the
+ :class:`MessageRequest` object until the notifications either expires,
+ is acknowledged by the client, or the callback url is reached. The
+ attributes of interest are: ``expired, called_back, acknowledged`` and
+ their *_at* variants as explained in the API documentation.
+
+ This function returns ``None`` when the request has expired or been
+ acknowledged, so that a typical handling of a priority-2 notification
+ can look like this::
+
+ request = client.send_message("Urgent notification", priority=2)
+ while not request.poll():
+ # do something
+ time.sleep(5)
+ """
if (self.receipt and not any(getattr(self, parameter)
for parameter in self.parameters)):
request = Request("get", RECEIPT_URL + self.receipt + ".json", {})
@@ -78,6 +141,14 @@ class MessageRequest(Request):
return request
class Client:
+ """This is the main class of the module. It represents a specific Pushover
+ user to whom messages will be sent when calling the :func:`send_message`
+ method.
+
+ * ``user``: the Pushover's ID of the user.
+ * ``device``: if not ``None`` further ties the Client object to the
+ specified device.
+ """
def __init__(self, user, device=None):
self.user = user
@@ -85,6 +156,11 @@ class Client:
self.devices = []
def verify(self, device=None):
+ """Verify that the Client object is tied to an existing Pushover user
+ and fetches a list of this user active devices accessible in the
+ :attr:`devices` attribute. Returns a boolean depending of the validity
+ of the user.
+ """
payload = {"user": self.user}
device = device or self.device
if device:
@@ -98,8 +174,18 @@ class Client:
return True
def send_message(self, message, **kwords):
+ """Send a message to the user. It is possible to specify additional
+ properties of the message by passing keyword arguments. The list of
+ valid keywords is ``title, priority, sound, callback, timestamp, url,
+ url_title, device, retry and expire`` which are described in the
+ Pushover API documentation. For convenience, you can simply set
+ ``timestamp=True`` to set the timestamp to the current timestamp.
+
+ This method returns a :class:`MessageRequest` object.
+ """
valid_keywords = ["title", "priority", "sound", "callback",
- "timestamp", "url", "url_title", "device"]
+ "timestamp", "url", "url_title", "device",
+ "retry", "expire"]
payload = {"message": message, "user": self.user}
if self.device: