def _setup(self): self.apobj = apprise.Apprise() self.tags = {} # first load configfile if specified tags = self.settings.get("tags", "") configfile = self.settings.get("configfile", "") self.log.debug("%s - %s" % (tags, configfile)) if tags and configfile: if configfile[:1] != "/": configfile = "/opt/mycroft/skills/apprise-skill/" + configfile self.log.debug("configfile - %s" % configfile) if os.path.isfile(configfile): config = apprise.AppriseConfig() config.add(configfile) self.apobj.add(config) taglist = tags.split(",") self.log.debug("taglist: %s" % taglist) for t in taglist: self.tags[t.strip().lower()] = t.strip() else: self.log.warn("config file does not exist: %s" % configfile) # second load tags and service-urls from settings for i in range(1, 4): tag = self.settings.get("tag{}".format(i), "") service = self.settings.get("service{}".format(i), "") if tag and service: self.tags[tag.lower()] = tag self.apobj.add(service, tag=tag) self.log.debug("tags - %s" % self.tags)
def get_service(hass, config, discovery_info=None): """Get the Apprise notification service.""" # Create our Apprise Asset Object asset = apprise.AppriseAsset(async_mode=False) # Create our Apprise Instance (reference our asset) a_obj = apprise.Apprise(asset=asset) if config.get(CONF_FILE): # Sourced from a Configuration File a_config = apprise.AppriseConfig() if not a_config.add(config[CONF_FILE]): _LOGGER.error("Invalid Apprise config url provided") return None if not a_obj.add(a_config): _LOGGER.error("Invalid Apprise config url provided") return None if config.get(CONF_URL): # Ordered list of URLs if not a_obj.add(config[CONF_URL]): _LOGGER.error("Invalid Apprise URL(s) supplied") return None return AppriseNotificationService(a_obj)
def __init__(self): if not os.path.exists(APPRISE_CONFIG_PATH): raise RuntimeError("No Apprise config found.") config = apprise.AppriseConfig() config.add(APPRISE_CONFIG_PATH) self.apobj = apprise.Apprise() self.apobj.add(config) self.queue = queue.Queue()
def __init__(self, enabled=True): if enabled and path.exists(APPRISE_CONFIG_PATH): self.apobj = apprise.Apprise() config = apprise.AppriseConfig() config.add(APPRISE_CONFIG_PATH) self.apobj.add(config) self.queue = queue.Queue() self.start_worker() self.enabled = True else: self.enabled = False
def __init__(self): if path.exists(APPRISE_CONFIG_PATH): log.info(f"Initializing Apprise handler using: {APPRISE_CONFIG_PATH}") self.apb = apprise.Apprise() config = apprise.AppriseConfig() config.add(APPRISE_CONFIG_PATH) # Get the service names from the config, not the Apprise instance when reading from config file for server in config.servers(): log.info(f"Found {server.service_name} configuration") self.enabled_handlers.append(server.service_name) self.apb.add(config) self.queue = queue.Queue() self.start_worker() self.enabled = True else: self.enabled = False log.info(f"No Apprise config found at {APPRISE_CONFIG_PATH}.") log.info(f"For notifications, see {APPRISE_CONFIG_PATH}_template")
def send(self, event, msg, key): if not check_module("apprise"): self.log_error( self._("Cannot send notification: apprise is not installed."), self. _("Install apprise by issuing 'pip install apprise' command."), ) return import apprise apprise_obj = apprise.Apprise() apprise_config = apprise.AppriseConfig() for c in key: apprise_config.add(c) apprise_obj.add(apprise_config) apprise_obj.notify( title=self.config.get("title"), body="%s: %s" % (event, msg) if msg else event, )
def post(self, request, key): """ Handle a POST request """ # our content content = {} if MIME_IS_FORM.match(request.content_type): content = {} form = NotifyForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) elif MIME_IS_JSON.match(request.content_type): # Prepare our default response try: # load our JSON content content = json.loads(request.body.decode('utf-8')) except (AttributeError, ValueError): # could not parse JSON response... return HttpResponse(_('Invalid JSON specified.'), status=ResponseCode.bad_request) if not content: # We could not handle the Content-Type return HttpResponse(_('The message format is not supported.'), status=ResponseCode.bad_request) # Some basic error checking if not content.get('body') or \ content.get('type', apprise.NotifyType.INFO) \ not in apprise.NOTIFY_TYPES: return HttpResponse(_('An invalid payload was specified.'), status=ResponseCode.bad_request) # If we get here, we have enough information to generate a notification # with. config, format = ConfigCache.get(key) if config is None: # The returned value of config and format tell a rather cryptic # story; this portion could probably be updated in the future. # but for now it reads like this: # config == None and format == None: We had an internal error # config == None and format != None: we simply have no data # config != None: we simply have no data if format is not None: # no content to return return HttpResponse( _('There was no configuration found.'), status=ResponseCode.no_content, ) # Something went very wrong; return 500 return HttpResponse( _('An error occured accessing configuration.'), status=ResponseCode.internal_server_error, ) # Prepare our apprise object a_obj = apprise.Apprise() # Create an apprise config object ac_obj = apprise.AppriseConfig() # Load our configuration ac_obj.add_config(config, format=format) # Add our configuration a_obj.add(ac_obj) # Perform our notification at this point result = a_obj.notify( content.get('body'), title=content.get('title', ''), notify_type=content.get('type', apprise.NotifyType.INFO), tag=content.get('tag'), ) if not result: # If at least one notification couldn't be sent; change up # the response to a 424 error code return HttpResponse( _('One or more notification could not be sent.'), status=ResponseCode.failed_dependency) # Return our retrieved content return HttpResponse(_('Notification(s) sent.'), status=ResponseCode.okay)
def post(self, request, key): """ Handle a POST request """ # our content content = {} if MIME_IS_FORM.match(request.content_type): content = {} form = AddByConfigForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) form = AddByUrlForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) elif MIME_IS_JSON.match(request.content_type): # Prepare our default response try: # load our JSON content content = json.loads(request.body.decode('utf-8')) except (AttributeError, ValueError): # could not parse JSON response... return HttpResponse(_('Invalid JSON specified.'), status=ResponseCode.bad_request) if not content: return HttpResponse(_('The message format is not supported.'), status=ResponseCode.bad_request) # Create ourselves an apprise object to work with a_obj = apprise.Apprise() if 'urls' in content: # Load our content a_obj.add(content['urls']) if not len(a_obj): # No URLs were loaded return HttpResponse( _('No valid URLs were found.'), status=ResponseCode.bad_request, ) if not ConfigCache.put(key, '\r\n'.join([s.url() for s in a_obj]), apprise.ConfigFormat.TEXT): return HttpResponse( _('The configuration could not be saved.'), status=ResponseCode.internal_server_error, ) elif 'config' in content: fmt = content.get('format', '').lower() if fmt not in [i[0] for i in CONFIG_FORMATS]: # Format must be one supported by apprise return HttpResponse( _('The format specified is invalid.'), status=ResponseCode.bad_request, ) # prepare our apprise config object ac_obj = apprise.AppriseConfig() if fmt == AUTO_DETECT_CONFIG_KEYWORD: # By setting format to None, it is automatically detected from # within the add_config() call fmt = None # Load our configuration if not ac_obj.add_config(content['config'], format=fmt): # The format could not be detected return HttpResponse( _('The configuration format could not be detected.'), status=ResponseCode.bad_request, ) # Add our configuration a_obj.add(ac_obj) if not len(a_obj): # No specified URL(s) were loaded due to # mis-configuration on the caller's part return HttpResponse( _('No valid URL(s) were specified.'), status=ResponseCode.bad_request, ) if not ConfigCache.put( key, content['config'], fmt=ac_obj[0].config_format): # Something went very wrong; return 500 return HttpResponse( _('An error occured saving configuration.'), status=ResponseCode.internal_server_error, ) else: # No configuration specified; we're done return HttpResponse( _('No configuration specified.'), status=ResponseCode.bad_request, ) # If we reach here; we successfully loaded the configuration so we can # go ahead and write it to disk and alert our caller of the success. return HttpResponse( _('Successfully saved configuration.'), status=ResponseCode.okay, )
import time import os.path import automationhat import apprise alarm_sounding = False script_dir = os.path.dirname(os.path.abspath(__file__)) # Configure notifications. You can use many different services. apobj = apprise.Apprise() config = apprise.AppriseConfig() config.add(script_dir + '/.apprise') apobj.add(config) print("Arming in 10 seconds") time.sleep(10) print("Armed!") while True: # Check the current state of the PIR sensor motion_detected = automationhat.input.three.read() # If new motion detected sound the alarm if motion_detected and alarm_sounding != True: print("Motion detected, loud noise time") #automationhat.relay.one.on() alarm_sounding = True apobj.notify(
def test_plugin_join_config_files(mock_post): """ NotifyJoin() Config File Cases """ content = """ urls: - join://%s@%s: - priority: -2 tag: join_int low - priority: "-2" tag: join_str_int low - priority: low tag: join_str low # This will take on normal (default) priority - priority: invalid tag: join_invalid - join://%s@%s: - priority: 2 tag: join_int emerg - priority: "2" tag: join_str_int emerg - priority: emergency tag: join_str emerg """ % ('a' * 32, 'b' * 32, 'c' * 32, 'd' * 32) # Disable Throttling to speed testing plugins.NotifyJoin.request_rate_per_sec = 0 # Prepare Mock mock_post.return_value = requests.Request() mock_post.return_value.status_code = requests.codes.ok # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 7 servers from that # 3x low # 3x emerg # 1x invalid (so takes on normal priority) assert len(ac.servers()) == 7 assert len(aobj) == 7 assert len([x for x in aobj.find(tag='low')]) == 3 for s in aobj.find(tag='low'): assert s.priority == JoinPriority.LOW assert len([x for x in aobj.find(tag='emerg')]) == 3 for s in aobj.find(tag='emerg'): assert s.priority == JoinPriority.EMERGENCY assert len([x for x in aobj.find(tag='join_str')]) == 2 assert len([x for x in aobj.find(tag='join_str_int')]) == 2 assert len([x for x in aobj.find(tag='join_int')]) == 2 assert len([x for x in aobj.find(tag='join_invalid')]) == 1 assert next(aobj.find(tag='join_invalid')).priority == \ JoinPriority.NORMAL # Notifications work assert aobj.notify(title="title", body="body") is True
def post(self, request, key): """ Handle a POST request """ # our content content = {} if MIME_IS_FORM.match(request.content_type): content = {} form = NotifyForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) elif MIME_IS_JSON.match(request.content_type): # Prepare our default response try: # load our JSON content content = json.loads(request.body.decode('utf-8')) except (AttributeError, ValueError): # could not parse JSON response... return HttpResponse(_('Invalid JSON specified.'), status=ResponseCode.bad_request) if not content: # We could not handle the Content-Type return HttpResponse(_('The message format is not supported.'), status=ResponseCode.bad_request) # Some basic error checking if not content.get('body') or \ content.get('type', apprise.NotifyType.INFO) \ not in apprise.NOTIFY_TYPES: return HttpResponse(_('An invalid payload was specified.'), status=ResponseCode.bad_request) # If we get here, we have enough information to generate a notification # with. config, format = ConfigCache.get(key) if config is None: # The returned value of config and format tell a rather cryptic # story; this portion could probably be updated in the future. # but for now it reads like this: # config == None and format == None: We had an internal error # config == None and format != None: we simply have no data # config != None: we simply have no data if format is not None: # no content to return return HttpResponse( _('There was no configuration found.'), status=ResponseCode.no_content, ) # Something went very wrong; return 500 return HttpResponse( _('An error occured accessing configuration.'), status=ResponseCode.internal_server_error, ) # Prepare our apprise object a_obj = apprise.Apprise() # Create an apprise config object ac_obj = apprise.AppriseConfig() try: # Write our file to a temporary file containing our configuration # so that we can read it back. In the future a change will be to # Apprise so that we can just directly write the configuration as # is to the AppriseConfig() object... but for now... with tempfile.NamedTemporaryFile() as f: # Write our content to disk f.write(config.encode()) f.flush() # Read our configuration back in to our configuration ac_obj.add('file://{}?format={}'.format(f.name, format)) # Add our configuration a_obj.add(ac_obj) # Perform our notification at this point a_obj.notify( content.get('body'), title=content.get('title', ''), notify_type=content.get('type', apprise.NotifyType.INFO), tag=content.get('tag'), ) except OSError: # We could not write the temporary file to disk return HttpResponse(_('The configuration could not be loaded.'), status=ResponseCode.internal_server_error) # Return our retrieved content return HttpResponse(_('Notification(s) sent.'), status=ResponseCode.okay)
def post(self, request, key): """ Handle a POST request """ # our content content = {} if MIME_IS_FORM.match(request.content_type): content = {} form = AddByConfigForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) form = AddByUrlForm(request.POST) if form.is_valid(): content.update(form.cleaned_data) elif MIME_IS_JSON.match(request.content_type): # Prepare our default response try: # load our JSON content content = json.loads(request.body.decode('utf-8')) except (AttributeError, ValueError): # could not parse JSON response... return HttpResponse(_('Invalid JSON specified.'), status=ResponseCode.bad_request) if not content: return HttpResponse(_('The message format is not supported.'), status=ResponseCode.bad_request) # Create ourselves an apprise object to work with a_obj = apprise.Apprise() if 'urls' in content: # Load our content a_obj.add(content['urls']) if not len(a_obj): # No URLs were loaded return HttpResponse( _('No valid URLs were found.'), status=ResponseCode.bad_request, ) if not ConfigCache.put(key, '\r\n'.join([s.url() for s in a_obj]), apprise.ConfigFormat.TEXT): return HttpResponse( _('The configuration could not be saved.'), status=ResponseCode.internal_server_error, ) elif 'config' in content: fmt = content.get('format', '').lower() if fmt not in apprise.CONFIG_FORMATS: # Format must be one supported by apprise return HttpResponse( _('The format specified is invalid.'), status=ResponseCode.bad_request, ) # prepare our apprise config object ac_obj = apprise.AppriseConfig() try: # Write our file to a temporary file with tempfile.NamedTemporaryFile() as f: # Write our content to disk f.write(content['config'].encode()) f.flush() if not ac_obj.add('file://{}?format={}'.format( f.name, fmt)): # Bad Configuration return HttpResponse( _('The configuration specified is invalid.'), status=ResponseCode.bad_request, ) # Add our configuration a_obj.add(ac_obj) if not len(a_obj): # No specified URL(s) were loaded due to # mis-configuration on the caller's part return HttpResponse( _('No valid URL(s) were specified.'), status=ResponseCode.bad_request, ) except OSError: # We could not write the temporary file to disk return HttpResponse( _('The configuration could not be loaded.'), status=ResponseCode.internal_server_error, ) if not ConfigCache.put(key, content['config'], fmt=fmt): # Something went very wrong; return 500 return HttpResponse( _('An error occured saving configuration.'), status=ResponseCode.internal_server_error, ) else: # No configuration specified; we're done return HttpResponse( _('No configuration specified.'), status=ResponseCode.bad_request, ) # If we reach here; we successfully loaded the configuration so we can # go ahead and write it to disk and alert our caller of the success. return HttpResponse( _('Successfully saved configuration.'), status=ResponseCode.okay, )
def test_plugin_ntfy_config_files(mock_post, mock_get): """ NotifyNtfy() Config File Cases """ content = """ urls: - ntfy://localhost/topic1: - priority: 1 tag: ntfy_int min - priority: "1" tag: ntfy_str_int min - priority: min tag: ntfy_str min # This will take on normal (default) priority - priority: invalid tag: ntfy_invalid - ntfy://localhost/topic2: - priority: 5 tag: ntfy_int max - priority: "5" tag: ntfy_str_int max - priority: emergency tag: ntfy_str max - priority: max tag: ntfy_str max """ # Disable Throttling to speed testing plugins.NotifyNtfy.request_rate_per_sec = 0 # Prepare Mock mock_post.return_value = requests.Request() mock_post.return_value.status_code = requests.codes.ok mock_get.return_value = requests.Request() mock_get.return_value.status_code = requests.codes.ok # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 8 servers from that # 3x min # 4x max # 1x invalid (so takes on normal priority) assert len(ac.servers()) == 8 assert len(aobj) == 8 assert len([x for x in aobj.find(tag='min')]) == 3 for s in aobj.find(tag='min'): assert s.priority == NtfyPriority.MIN assert len([x for x in aobj.find(tag='max')]) == 4 for s in aobj.find(tag='max'): assert s.priority == NtfyPriority.MAX assert len([x for x in aobj.find(tag='ntfy_str')]) == 3 assert len([x for x in aobj.find(tag='ntfy_str_int')]) == 2 assert len([x for x in aobj.find(tag='ntfy_int')]) == 2 assert len([x for x in aobj.find(tag='ntfy_invalid')]) == 1 assert next(aobj.find(tag='ntfy_invalid')).priority == \ NtfyPriority.NORMAL
def test_plugin_opsgenie_config_files(mock_post): """ NotifyOpsgenie() Config File Cases """ content = """ urls: - opsgenie://apikey/user: - priority: 1 tag: opsgenie_int low - priority: "1" tag: opsgenie_str_int low - priority: "p1" tag: opsgenie_pstr_int low - priority: low tag: opsgenie_str low # This will take on moderate (default) priority - priority: invalid tag: opsgenie_invalid - opsgenie://apikey2/user2: - priority: 5 tag: opsgenie_int emerg - priority: "5" tag: opsgenie_str_int emerg - priority: "p5" tag: opsgenie_pstr_int emerg - priority: emergency tag: opsgenie_str emerg """ # Disable Throttling to speed testing apprise.plugins.NotifyOpsgenie.request_rate_per_sec = 0 # Prepare Mock mock_post.return_value = requests.Request() mock_post.return_value.status_code = requests.codes.ok # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 9 servers from that # 4x low # 4x emerg # 1x invalid (so takes on normal priority) assert len(ac.servers()) == 9 assert len(aobj) == 9 assert len([x for x in aobj.find(tag='low')]) == 4 for s in aobj.find(tag='low'): assert s.priority == OpsgeniePriority.LOW assert len([x for x in aobj.find(tag='emerg')]) == 4 for s in aobj.find(tag='emerg'): assert s.priority == OpsgeniePriority.EMERGENCY assert len([x for x in aobj.find(tag='opsgenie_str')]) == 2 assert len([x for x in aobj.find(tag='opsgenie_str_int')]) == 2 assert len([x for x in aobj.find(tag='opsgenie_pstr_int')]) == 2 assert len([x for x in aobj.find(tag='opsgenie_int')]) == 2 assert len([x for x in aobj.find(tag='opsgenie_invalid')]) == 1 assert next(aobj.find(tag='opsgenie_invalid')).priority == \ OpsgeniePriority.NORMAL
def test_plugin_dapnet_config_files(mock_post): """ NotifyDapnet() Config File Cases """ content = """ urls: - dapnet://user:pass@DF1ABC: - priority: 0 tag: dapnet_int normal - priority: "0" tag: dapnet_str_int normal - priority: normal tag: dapnet_str normal # This will take on normal (default) priority - priority: invalid tag: dapnet_invalid - dapnet://user1:pass2@DF1ABC: - priority: 1 tag: dapnet_int emerg - priority: "1" tag: dapnet_str_int emerg - priority: emergency tag: dapnet_str emerg """ # Disable Throttling to speed testing plugins.NotifyDapnet.request_rate_per_sec = 0 # Prepare Mock mock_post.return_value = requests.Request() mock_post.return_value.status_code = requests.codes.created # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 7 servers from that # 4x normal (invalid + 3 exclusivly specified to be so) # 3x emerg assert len(ac.servers()) == 7 assert len(aobj) == 7 assert len([x for x in aobj.find(tag='normal')]) == 3 for s in aobj.find(tag='normal'): assert s.priority == DapnetPriority.NORMAL assert len([x for x in aobj.find(tag='emerg')]) == 3 for s in aobj.find(tag='emerg'): assert s.priority == DapnetPriority.EMERGENCY assert len([x for x in aobj.find(tag='dapnet_str')]) == 2 assert len([x for x in aobj.find(tag='dapnet_str_int')]) == 2 assert len([x for x in aobj.find(tag='dapnet_int')]) == 2 assert len([x for x in aobj.find(tag='dapnet_invalid')]) == 1 assert next(aobj.find(tag='dapnet_invalid')).priority == \ DapnetPriority.NORMAL # Notifications work assert aobj.notify(title="title", body="body") is True
def get(self, request, key): """ Handle a POST request """ # Now build our tag response that identifies all of the tags # and the URL's they're associated with # { # "tags": ["tag1', "tag2", "tag3"], # "urls": [ # { # "url": "windows://", # "tags": [], # }, # { # "url": "mailto://*****:*****@gmail.com" # "tags": ["tag1", "tag2", "tag3"] # } # ] # } response = { 'tags': set(), 'urls': [], } # Privacy flag privacy = bool(request.GET.get('privacy', False)) config, format = ConfigCache.get(key) if config is None: # The returned value of config and format tell a rather cryptic # story; this portion could probably be updated in the future. # but for now it reads like this: # config == None and format == None: We had an internal error # config == None and format != None: we simply have no data # config != None: we simply have no data if format is not None: # no content to return return JsonResponse( response, encoder=JSONEncoder, safe=False, status=ResponseCode.no_content, ) # Something went very wrong; return 500 response['error'] = _('There was no configuration found.') return JsonResponse( response, encoder=JSONEncoder, safe=False, status=ResponseCode.internal_server_error, ) # Prepare our apprise object a_obj = apprise.Apprise() # Create an apprise config object ac_obj = apprise.AppriseConfig() # Load our configuration ac_obj.add_config(config, format=format) # Add our configuration a_obj.add(ac_obj) for notification in a_obj: # Set Notification response['urls'].append({ 'url': notification.url(privacy=privacy), 'tags': notification.tags, }) # Store Tags response['tags'] |= notification.tags # Return our retrieved content return JsonResponse(response, encoder=JSONEncoder, safe=False, status=ResponseCode.okay)
def get(self, request, key): """ Handle a POST request """ # Now build our tag response that identifies all of the tags # and the URL's they're associated with # { # "tags": ["tag1', "tag2", "tag3"], # "urls": [ # { # "url": "windows://", # "tags": [], # }, # { # "url": "mailto://*****:*****@gmail.com" # "tags": ["tag1", "tag2", "tag3"] # } # ] # } response = { 'tags': set(), 'urls': [], } # Privacy flag privacy = bool(request.GET.get('privacy', False)) config, format = ConfigCache.get(key) if config is None: # The returned value of config and format tell a rather cryptic # story; this portion could probably be updated in the future. # but for now it reads like this: # config == None and format == None: We had an internal error # config == None and format != None: we simply have no data # config != None: we simply have no data if format is not None: # no content to return return JsonResponse( response, encoder=JSONEncoder, safe=False, status=ResponseCode.no_content, ) # Something went very wrong; return 500 response['error'] = _('There was no configuration found.') return JsonResponse( response, encoder=JSONEncoder, safe=False, status=ResponseCode.internal_server_error, ) # Prepare our apprise object a_obj = apprise.Apprise() # Create an apprise config object ac_obj = apprise.AppriseConfig() try: # Write our file to a temporary file containing our configuration # so that we can read it back. In the future a change will be to # Apprise so that we can just directly write the configuration as # is to the AppriseConfig() object... but for now... with tempfile.NamedTemporaryFile() as f: # Write our content to disk f.write(config.encode()) f.flush() # Read our configuration back in to our configuration ac_obj.add('file://{}?format={}'.format(f.name, format)) # Add our configuration a_obj.add(ac_obj) for notification in a_obj: # Set Notification response['urls'].append({ 'url': notification.url(privacy=privacy), 'tags': notification.tags, }) # Store Tags response['tags'] |= notification.tags except OSError: # We could not write the temporary file to disk response['error'] = _('The configuration could not be loaded.'), return JsonResponse( response, encoder=JSONEncoder, safe=False, status=ResponseCode.internal_server_error, ) # Return our retrieved content return JsonResponse(response, encoder=JSONEncoder, safe=False, status=ResponseCode.okay)
def test_plugin_gnome_general(): """ NotifyGnome() General Checks """ # Our module base gi_name = 'gi' # First we do an import without the gi library available to ensure # we can handle cases when the library simply isn't available if gi_name in sys.modules: # Test cases where the gi library exists; we want to remove it # for the purpose of testing and capture the handling of the # library when it is missing del sys.modules[gi_name] reload(sys.modules['apprise.plugins.NotifyGnome']) # We need to fake our gnome environment for testing purposes since # the gi library isn't available in Travis CI gi = types.ModuleType(gi_name) gi.repository = types.ModuleType(gi_name + '.repository') gi.module = types.ModuleType(gi_name + '.module') mock_pixbuf = mock.Mock() mock_notify = mock.Mock() gi.repository.GdkPixbuf = \ types.ModuleType(gi_name + '.repository.GdkPixbuf') gi.repository.GdkPixbuf.Pixbuf = mock_pixbuf gi.repository.Notify = mock.Mock() gi.repository.Notify.init.return_value = True gi.repository.Notify.Notification = mock_notify # Emulate require_version function: gi.require_version = mock.Mock(name=gi_name + '.require_version') # Force the fake module to exist sys.modules[gi_name] = gi sys.modules[gi_name + '.repository'] = gi.repository sys.modules[gi_name + '.repository.Notify'] = gi.repository.Notify # Notify Object notify_obj = mock.Mock() notify_obj.set_urgency.return_value = True notify_obj.set_icon_from_pixbuf.return_value = True notify_obj.set_image_from_pixbuf.return_value = True notify_obj.show.return_value = True mock_notify.new.return_value = notify_obj mock_pixbuf.new_from_file.return_value = True # The following libraries need to be reloaded to prevent # TypeError: super(type, obj): obj must be an instance or subtype of type # This is better explained in this StackOverflow post: # https://stackoverflow.com/questions/31363311/\ # any-way-to-manually-fix-operation-of-\ # super-after-ipython-reload-avoiding-ty # reload(sys.modules['apprise.plugins.NotifyGnome']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # Create our instance obj = apprise.Apprise.instantiate('gnome://', suppress_exceptions=False) assert obj is not None # Set our duration to 0 to speed up timeouts (for testing) obj.duration = 0 # Check that it found our mocked environments assert obj.enabled is True # Test url() call assert isinstance(obj.url(), six.string_types) is True # test notifications assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # test notification without a title assert obj.notify( title='', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?image=True', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?image=False', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test Priority (alias of urgency) obj = apprise.Apprise.instantiate('gnome://_/?priority=invalid', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.urgency == 1 assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?priority=high', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.urgency == 2 assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?priority=2', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.urgency == 2 assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test Urgeny obj = apprise.Apprise.instantiate('gnome://_/?urgency=invalid', suppress_exceptions=False) assert obj.urgency == 1 assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?urgency=high', suppress_exceptions=False) assert obj.urgency == 2 assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('gnome://_/?urgency=2', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyGnome) is True assert obj.urgency == 2 assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test configuration parsing content = """ urls: - gnome://: - priority: 0 tag: gnome_int low - priority: "0" tag: gnome_str_int low - priority: low tag: gnome_str low - urgency: 0 tag: gnome_int low - urgency: "0" tag: gnome_str_int low - urgency: low tag: gnome_str low # These will take on normal (default) urgency - priority: invalid tag: gnome_invalid - urgency: invalid tag: gnome_invalid - gnome://: - priority: 2 tag: gnome_int high - priority: "2" tag: gnome_str_int high - priority: high tag: gnome_str high - urgency: 2 tag: gnome_int high - urgency: "2" tag: gnome_str_int high - urgency: high tag: gnome_str high """ # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 14 servers from that # 6x low # 6x high # 2x invalid (so takes on normal urgency) assert len(ac.servers()) == 14 assert len(aobj) == 14 assert len([x for x in aobj.find(tag='low')]) == 6 for s in aobj.find(tag='low'): assert s.urgency == GnomeUrgency.LOW assert len([x for x in aobj.find(tag='high')]) == 6 for s in aobj.find(tag='high'): assert s.urgency == GnomeUrgency.HIGH assert len([x for x in aobj.find(tag='gnome_str')]) == 4 assert len([x for x in aobj.find(tag='gnome_str_int')]) == 4 assert len([x for x in aobj.find(tag='gnome_int')]) == 4 assert len([x for x in aobj.find(tag='gnome_invalid')]) == 2 for s in aobj.find(tag='gnome_invalid'): assert s.urgency == GnomeUrgency.NORMAL # Test our loading of our icon exception; it will still allow the # notification to be sent mock_pixbuf.new_from_file.side_effect = AttributeError() assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Undo our change mock_pixbuf.new_from_file.side_effect = None # Test our exception handling during initialization sys.modules['gi.repository.Notify']\ .Notification.new.return_value = None sys.modules['gi.repository.Notify']\ .Notification.new.side_effect = AttributeError() assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is False # Undo our change sys.modules['gi.repository.Notify']\ .Notification.new.side_effect = None # Toggle our testing for when we can't send notifications because the # package has been made unavailable to us obj.enabled = False assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is False # Test the setting of a the urgency (through priority keyword) apprise.plugins.NotifyGnome(priority=0) # Verify this all works in the event a ValueError is also thronw # out of the call to gi.require_version() # Emulate require_version function: gi.require_version.side_effect = ValueError() # The following libraries need to be reloaded to prevent # TypeError: super(type, obj): obj must be an instance or subtype of type # This is better explained in this StackOverflow post: # https://stackoverflow.com/questions/31363311/\ # any-way-to-manually-fix-operation-of-\ # super-after-ipython-reload-avoiding-ty # reload(sys.modules['apprise.plugins.NotifyGnome']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # We can now no longer load our instance # The object internally is marked disabled obj = apprise.Apprise.instantiate('gnome://', suppress_exceptions=False) assert obj is None
def test_plugin_dbus_general(mock_mainloop, mock_byte, mock_bytearray, mock_interface, mock_sessionbus): """ NotifyDBus() General Tests """ # Our module base gi_name = 'gi' # First we do an import without the gi library available to ensure # we can handle cases when the library simply isn't available if gi_name in sys.modules: # Test cases where the gi library exists; we want to remove it # for the purpose of testing and capture the handling of the # library when it is missing del sys.modules[gi_name] reload(sys.modules['apprise.plugins.NotifyDBus']) # We need to fake our dbus environment for testing purposes since # the gi library isn't available in Travis CI gi = types.ModuleType(gi_name) gi.repository = types.ModuleType(gi_name + '.repository') mock_pixbuf = mock.Mock() mock_image = mock.Mock() mock_pixbuf.new_from_file.return_value = mock_image mock_image.get_width.return_value = 100 mock_image.get_height.return_value = 100 mock_image.get_rowstride.return_value = 1 mock_image.get_has_alpha.return_value = 0 mock_image.get_bits_per_sample.return_value = 8 mock_image.get_n_channels.return_value = 1 mock_image.get_pixels.return_value = '' gi.repository.GdkPixbuf = \ types.ModuleType(gi_name + '.repository.GdkPixbuf') gi.repository.GdkPixbuf.Pixbuf = mock_pixbuf # Emulate require_version function: gi.require_version = mock.Mock(name=gi_name + '.require_version') # Force the fake module to exist sys.modules[gi_name] = gi sys.modules[gi_name + '.repository'] = gi.repository # Exception Handling mock_mainloop.qt.DBusQtMainLoop.return_value = True mock_mainloop.qt.DBusQtMainLoop.side_effect = ImportError sys.modules['dbus.mainloop.qt'] = mock_mainloop.qt reload(sys.modules['apprise.plugins.NotifyDBus']) mock_mainloop.qt.DBusQtMainLoop.side_effect = None # Python v2.x mock_mainloop.glib.DBusGMainLoop.return_value = True mock_mainloop.glib.DBusGMainLoop.side_effect = ImportError() # Python 3.x mock_mainloop.glib.NativeMainLoop.return_value = True mock_mainloop.glib.NativeMainLoop.side_effect = ImportError() sys.modules['dbus.mainloop.glib'] = mock_mainloop.glib reload(sys.modules['apprise.plugins.NotifyDBus']) mock_mainloop.glib.DBusGMainLoop.side_effect = None mock_mainloop.glib.NativeMainLoop.side_effect = None # The following libraries need to be reloaded to prevent # TypeError: super(type, obj): obj must be an instance or subtype of type # This is better explained in this StackOverflow post: # https://stackoverflow.com/questions/31363311/\ # any-way-to-manually-fix-operation-of-\ # super-after-ipython-reload-avoiding-ty # reload(sys.modules['apprise.plugins.NotifyDBus']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # Create our instance (identify all supported types) obj = apprise.Apprise.instantiate('dbus://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('dbus://_/') obj = apprise.Apprise.instantiate('kde://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('kde://_/') obj = apprise.Apprise.instantiate('qt://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('qt://_/') obj = apprise.Apprise.instantiate('glib://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('glib://_/') obj.duration = 0 # Test our class loading using a series of arguments with pytest.raises(TypeError): apprise.plugins.NotifyDBus(**{'schema': 'invalid'}) # Set our X and Y coordinate and try the notification assert apprise.plugins.NotifyDBus( x_axis=0, y_axis=0, **{'schema': 'dbus'})\ .notify(title='', body='body', notify_type=apprise.NotifyType.INFO) is True # test notifications assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # test notification without a title assert obj.notify( title='', body='body', notify_type=apprise.NotifyType.INFO) is True # Test our arguments through the instantiate call obj = apprise.Apprise.instantiate('dbus://_/?image=True', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('dbus://_/') assert re.search('image=yes', obj.url()) assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?image=False', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.url().startswith('dbus://_/') assert re.search('image=no', obj.url()) assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test priority (alias to urgency) handling obj = apprise.Apprise.instantiate('dbus://_/?priority=invalid', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?priority=high', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?priority=2', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test urgency handling obj = apprise.Apprise.instantiate('dbus://_/?urgency=invalid', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?urgency=high', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?urgency=2', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True obj = apprise.Apprise.instantiate('dbus://_/?urgency=', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Test x/y obj = apprise.Apprise.instantiate('dbus://_/?x=5&y=5', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True assert isinstance(obj.url(), six.string_types) is True assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True with pytest.raises(TypeError): obj = apprise.Apprise.instantiate('dbus://_/?x=invalid&y=invalid', suppress_exceptions=False) # Test configuration parsing content = """ urls: - dbus://: - priority: 0 tag: dbus_int low - priority: "0" tag: dbus_str_int low - priority: low tag: dbus_str low - urgency: 0 tag: dbus_int low - urgency: "0" tag: dbus_str_int low - urgency: low tag: dbus_str low # These will take on normal (default) urgency - priority: invalid tag: dbus_invalid - urgency: invalid tag: dbus_invalid - dbus://: - priority: 2 tag: dbus_int high - priority: "2" tag: dbus_str_int high - priority: high tag: dbus_str high - urgency: 2 tag: dbus_int high - urgency: "2" tag: dbus_str_int high - urgency: high tag: dbus_str high """ # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 14 servers from that # 6x low # 6x high # 2x invalid (so takes on normal urgency) assert len(ac.servers()) == 14 assert len(aobj) == 14 assert len([x for x in aobj.find(tag='low')]) == 6 for s in aobj.find(tag='low'): assert s.urgency == DBusUrgency.LOW assert len([x for x in aobj.find(tag='high')]) == 6 for s in aobj.find(tag='high'): assert s.urgency == DBusUrgency.HIGH assert len([x for x in aobj.find(tag='dbus_str')]) == 4 assert len([x for x in aobj.find(tag='dbus_str_int')]) == 4 assert len([x for x in aobj.find(tag='dbus_int')]) == 4 assert len([x for x in aobj.find(tag='dbus_invalid')]) == 2 for s in aobj.find(tag='dbus_invalid'): assert s.urgency == DBusUrgency.NORMAL # If our underlining object throws for whatever rea on, we will # gracefully fail mock_notify = mock.Mock() mock_interface.return_value = mock_notify mock_notify.Notify.side_effect = AttributeError() assert obj.notify( title='', body='body', notify_type=apprise.NotifyType.INFO) is False mock_notify.Notify.side_effect = None # Test our loading of our icon exception; it will still allow the # notification to be sent mock_pixbuf.new_from_file.side_effect = AttributeError() assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Undo our change mock_pixbuf.new_from_file.side_effect = None # Test our exception handling during initialization # Toggle our testing for when we can't send notifications because the # package has been made unavailable to us obj.enabled = False assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is False # Test the setting of a the urgency apprise.plugins.NotifyDBus(urgency=0) # # We can still notify if the gi library is the only inaccessible # compontent # # Emulate require_version function: gi.require_version.side_effect = ImportError() # The following libraries need to be reloaded to prevent # TypeError: super(type, obj): obj must be an instance or subtype of type # This is better explained in this StackOverflow post: # https://stackoverflow.com/questions/31363311/\ # any-way-to-manually-fix-operation-of-\ # super-after-ipython-reload-avoiding-ty # reload(sys.modules['apprise.plugins.NotifyDBus']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # Create our instance obj = apprise.Apprise.instantiate('glib://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True obj.duration = 0 # Test url() call assert isinstance(obj.url(), six.string_types) is True # Our notification succeeds even though the gi library was not loaded assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Verify this all works in the event a ValueError is also thronw # out of the call to gi.require_version() mock_sessionbus.side_effect = DBusException('test') # Handle Dbus Session Initialization error assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is False # Return side effect to normal mock_sessionbus.side_effect = None # Emulate require_version function: gi.require_version.side_effect = ValueError() # The following libraries need to be reloaded to prevent # TypeError: super(type, obj): obj must be an instance or subtype of type # This is better explained in this StackOverflow post: # https://stackoverflow.com/questions/31363311/\ # any-way-to-manually-fix-operation-of-\ # super-after-ipython-reload-avoiding-ty # reload(sys.modules['apprise.plugins.NotifyDBus']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # Create our instance obj = apprise.Apprise.instantiate('glib://', suppress_exceptions=False) assert isinstance(obj, apprise.plugins.NotifyDBus) is True obj.duration = 0 # Test url() call assert isinstance(obj.url(), six.string_types) is True # Our notification succeeds even though the gi library was not loaded assert obj.notify(title='title', body='body', notify_type=apprise.NotifyType.INFO) is True # Force a global import error _session_bus = sys.modules['dbus'] sys.modules['dbus'] = compile('raise ImportError()', 'dbus', 'exec') # Reload our modules reload(sys.modules['apprise.plugins.NotifyDBus']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise']) # We can no longer instantiate an instance because dbus has been # officialy marked unavailable and thus the module is marked # as such obj = apprise.Apprise.instantiate('glib://', suppress_exceptions=False) assert obj is None # Since playing with the sys.modules is not such a good idea, # let's just put our old configuration back: sys.modules['dbus'] = _session_bus # Reload our modules reload(sys.modules['apprise.plugins.NotifyDBus']) reload(sys.modules['apprise.plugins']) reload(sys.modules['apprise.Apprise']) reload(sys.modules['apprise'])
def test_plugin_growl_config_files(mock_gntp): """ NotifyGrowl() Config File Cases """ content = """ urls: - growl://[email protected]: - priority: -2 tag: growl_int low - priority: "-2" tag: growl_str_int low - priority: low tag: growl_str low # This will take on moderate (default) priority - priority: invalid tag: growl_invalid - growl://[email protected]: - priority: 2 tag: growl_int emerg - priority: "2" tag: growl_str_int emerg - priority: emergency tag: growl_str emerg """ # Disable Throttling to speed testing apprise.plugins.NotifyGrowl.request_rate_per_sec = 0 mock_notifier = mock.Mock() mock_gntp.return_value = mock_notifier mock_notifier.notify.return_value = True # Create ourselves a config object ac = apprise.AppriseConfig() assert ac.add_config(content=content) is True aobj = apprise.Apprise() # Add our configuration aobj.add(ac) # We should be able to read our 7 servers from that # 3x low # 3x emerg # 1x invalid (so takes on normal priority) assert len(ac.servers()) == 7 assert len(aobj) == 7 assert len([x for x in aobj.find(tag='low')]) == 3 for s in aobj.find(tag='low'): assert s.priority == GrowlPriority.LOW assert len([x for x in aobj.find(tag='emerg')]) == 3 for s in aobj.find(tag='emerg'): assert s.priority == GrowlPriority.EMERGENCY assert len([x for x in aobj.find(tag='growl_str')]) == 2 assert len([x for x in aobj.find(tag='growl_str_int')]) == 2 assert len([x for x in aobj.find(tag='growl_int')]) == 2 assert len([x for x in aobj.find(tag='growl_invalid')]) == 1 assert next(aobj.find(tag='growl_invalid')).priority == \ GrowlPriority.NORMAL