<commit_before># Copyright 2013-2014, <NAME>, <EMAIL>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Part of 'hiss' the asynchronous notification library

import uuid
import asyncio
import logging
from itertools import product
from collections import namedtuple

from hiss.target import Target
from hiss.exception import NotifierError
from hiss.notification import Notification
from hiss.handler.gntp import GNTPHandler
from hiss.handler.snp import SNPHandler
from hiss.handler.xbmc import XBMCHandler

__all__ = ['Notifier', 'USE_NOTIFIER', 'USE_REGISTERED']

NotificationInfo = namedtuple('NotificationInfo', ['name', 'title', 'text',
                                                   'icon', 'sound', 'enabled'])

USE_NOTIFIER = -1
USE_REGISTERED = -2

class Notifier(object):
    """Maintains a list of targets to handle notifications for.

    :param name:      The name of this notifier
    :type name:       string
    :param signature: The MIME style application signature for this notifier
                      of the form :samp:`application/x-vnd.{vendor}.{app}`
    :type signature:  string
    :param icon:      Notifier icon. Used when registering the notifier and
                      as the default icon for notifications.
    :type icon:       :class:`~hiss.resource.Icon` or string
    :param loop:      :mod:`asyncio` event loop to use.
    :type loop:       :class:`asyncio.BaseEventLoop`
    """

    #TODO: standardised icon and sound handling between handler types
    def __init__(self, name, signature,
                 icon=None, sound=None,
                 event_handler=None,
                 uid=None, loop=None):
        self.name = name
        self.signature = signature
        self.icon = icon
        self.sound = sound
        
        self.notification_classes = {}
        self.targets = TargetList()

        self._event_handler = event_handler

        if uid is None:
            self.uid = self._unique_id()
        else:
            self.uid = uid

        if loop is None:
            self.loop = asyncio.get_event_loop()
        else:
            self.loop = loop

        self._handlers = {}
        self._notifications = {}

    def add_notification(self, name, title=None, text=None,
                         icon=None, sound=None,
                         enabled=True, class_id=None):
        """Add a notification class.

        :param name:          Notification class name
        :type name:           str
        :param title:         Default notification title
        :type title:          str or None
        :param text:          Default notification text
        :type text:           str or None
        :param icon:          Default notification icon
        :type icon:           str or None
        :param sound:         Default notification sound
        :type sound:          str or None
        :param enabled:       Whether the notification is enabled or not
        :type enabled:        bool
        :param class_id:      The class id to use. If not provided one will be
                              generated.
        :type class_id:       int
        :returns:             The class id of the newly added notification
        :rtype:               int
        
        Default values will be used when creating a notification with
        :meth:`~hiss.notifier.Notifier.create_notification`
        """

        ni = NotificationInfo(name, title, text, icon, sound, enabled)

        if class_id is None or class_id in self.notification_classes:
            if len(self.notification_classes) == 0:
                class_id = 1
            else:
                class_id = max(self.notification_classes.keys()) + 1

        self.notification_classes[class_id] = ni

        return class_id

    def create_notification(self, class_id=-1, name='',
                            title=USE_REGISTERED, text=USE_REGISTERED,
                            icon=USE_REGISTERED, sound=USE_REGISTERED):
        """Create a notification that is ready to send.

        Either ``class_id`` or ``name`` can be provided. If ``class_id`` is
        provided it will be used instead of ``name`` to
        lookup the defaults registered in
        :meth:`~hiss.notifier.Notifier.add_notification`

        :param class_id:   The notification class id
        :type class_id:    int
        :param name:       The notification name
        :type name:        str
        :param title:      The title of the notification
        :type title:       str, None for no title or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use title provided during registration
        :param text:       The text to display in the notification
        :type text:        str, None for no text or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use text provided during registration
        :param icon:       Icon to display
        :type icon:        str, :class:`~hiss.resource.Icon`, None for no
                           icon or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use icon provided during registration
        :param sound:      Sound to play when showing notification
        :type sound:       str, None for no sound or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use sound provided during registration
        """

        if class_id != -1:
            if class_id not in self.notification_classes:
                raise NotifierError('%d is not a known notification class id' % \
                                 str(class_id))
            info = self.notification_classes[class_id]
        elif name != '':
            info = self.find_notification(name)
        else:
            raise NotifierError('Either a class id or name must be specified.',
                                'hiss.notifier.Notifier')

        if title is USE_REGISTERED:
            title = info.title

        if text is USE_REGISTERED:
            text = info.text

        if icon is None:
            if info.icon is not None:
                icon = info.icon
            else:
                icon = self.icon

        if sound is None:
            if info.sound is not None:
                sound = info.sound
            else:
                sound = self.sound

        uid = self._unique_id()

        n =  Notification(title, text, icon, sound, uid=uid)
        n.name = info.name
        n.class_id = class_id
        n.notifier = self
        return n

    def find_notification(self, name):
        for value in self.notification_classes.values():
            if value.name == name:
                return value

    @asyncio.coroutine
    def add_target(self, targets):
        """Add a single target or list of targets to the known targets
        and connects to them

        :param targets: The Target or list of Targets to add.
        :type targets:  :class:`~hiss.target.Target`
        :returns:       Result dict or list of dict if more than one target added.
        """

        if isinstance(targets, Target):
            targets = [targets]
<commit_msg>* Changed USE_REGISTER and USE_NOTIFIER to sentinel objects. * Changed default sound for notifications to no sound<commit_after># Copyright 2013-2014, <NAME>, <EMAIL>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Part of 'hiss' the asynchronous notification library

import uuid
import asyncio
import logging
from itertools import product
from collections import namedtuple

from hiss.target import Target
from hiss.exception import NotifierError
from hiss.notification import Notification
from hiss.handler.gntp import GNTPHandler
from hiss.handler.snp import SNPHandler
from hiss.handler.xbmc import XBMCHandler

__all__ = ['Notifier', 'USE_NOTIFIER', 'USE_REGISTERED']

NotificationInfo = namedtuple('NotificationInfo', ['name', 'title', 'text',
                                                   'icon', 'sound', 'enabled'])

USE_NOTIFIER = object()
USE_REGISTERED = object()

class Notifier(object):
    """Maintains a list of targets to handle notifications for.

    :param name:      The name of this notifier
    :type name:       string
    :param signature: The MIME style application signature for this notifier
                      of the form :samp:`application/x-vnd.{vendor}.{app}`
    :type signature:  string
    :param icon:      Notifier icon. Used when registering the notifier and
                      as the default icon for notifications.
    :type icon:       :class:`~hiss.resource.Icon` or string
    :param loop:      :mod:`asyncio` event loop to use.
    :type loop:       :class:`asyncio.BaseEventLoop`
    """

    #TODO: standardised icon and sound handling between handler types
    def __init__(self, name, signature,
                 icon=None, sound=None,
                 event_handler=None,
                 uid=None, loop=None):
        self.name = name
        self.signature = signature
        self.icon = icon
        self.sound = sound
        
        self.notification_classes = {}
        self.targets = TargetList()

        self._event_handler = event_handler

        if uid is None:
            self.uid = self._unique_id()
        else:
            self.uid = uid

        if loop is None:
            self.loop = asyncio.get_event_loop()
        else:
            self.loop = loop

        self._handlers = {}
        self._notifications = {}

    def add_notification(self, name, title=None, text=None,
                         icon=None, sound=None,
                         enabled=True, class_id=None):
        """Add a notification class.

        :param name:          Notification class name
        :type name:           str
        :param title:         Default notification title
        :type title:          str or None
        :param text:          Default notification text
        :type text:           str or None
        :param icon:          Default notification icon
        :type icon:           str or None
        :param sound:         Default notification sound
        :type sound:          str or None
        :param enabled:       Whether the notification is enabled or not
        :type enabled:        bool
        :param class_id:      The class id to use. If not provided one will be
                              generated.
        :type class_id:       int
        :returns:             The class id of the newly added notification
        :rtype:               int
        
        Default values will be used when creating a notification with
        :meth:`~hiss.notifier.Notifier.create_notification`
        """

        ni = NotificationInfo(name, title, text, icon, sound, enabled)

        if class_id is None or class_id in self.notification_classes:
            if len(self.notification_classes) == 0:
                class_id = 1
            else:
                class_id = max(self.notification_classes.keys()) + 1

        self.notification_classes[class_id] = ni

        return class_id

    def create_notification(self, class_id=-1, name='',
                            title=USE_REGISTERED, text=USE_REGISTERED,
                            icon=USE_REGISTERED, sound=None):
        """Create a notification that is ready to send.

        Either ``class_id`` or ``name`` can be provided. If ``class_id`` is
        provided it will be used instead of ``name`` to
        lookup the defaults registered in
        :meth:`~hiss.notifier.Notifier.add_notification`

        :param class_id:   The notification class id
        :type class_id:    int
        :param name:       The notification name
        :type name:        str
        :param title:      The title of the notification
        :type title:       str, None for no title or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use title provided during registration,
                           :data:`~hiss.notifier.USE_NOTIFIER` to the use the
                           Notifier's name 
        :param text:       The text to display in the notification
        :type text:        str, None for no text or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use text provided during registration
        :param icon:       Icon to display
        :type icon:        str, :class:`~hiss.resource.Icon`, None for no
                           icon or
                           :data:`~hiss.notifier.USE_REGISTERED` (default)
                           to use icon provided during registration
        :param sound:      Sound to play when showing notification
        :type sound:       str, None (default) for no sound or
                           :data:`~hiss.notifier.USE_REGISTERED`
                           to use sound provided during registration
        """

        if class_id != -1:
            if class_id not in self.notification_classes:
                raise NotifierError('%d is not a known notification class id' % \
                                 str(class_id))
            registration_info = self.notification_classes[class_id]
        elif name != '':
            registration_info = self.find_notification(name)
        else:
            raise NotifierError('Either a class id or name must be specified.',
                                'hiss.notifier.Notifier')

        if title is USE_REGISTERED:
            title = registration_info.title
        elif title is USE_NOTIFIER:
            title = self.name

        if text is USE_REGISTERED:
            text = registration_info.text

        if icon is None:
            if registration_info.icon is not None:
                icon = registration_info.icon
            else:
                icon = self.icon

        if registration_info.sound is None:
            sound = None
        elif sound == USE_REGISTERED:
            sound = registration_info.sound

        uid = self._unique_id()

        n =  Notification(title, text, icon, sound, uid=uid)
        n.name = registration_info.name
        n.class_id = class_id
        n.notifier = self
        return n

    def find_notification(self, name):
        for value in self.notification_classes.values():
            if value.name == name:
                return value

    @asyncio.coroutine
    def add_target(self, targets):
        """Add a single target or list of targets to the known targets
        and connects to them

        :param targets: The Target or list of Targets to add.
        :type targets:  :class:`~hiss.target.Target`
        :returns:       Result dict or list of dict if more than one target added.
        """

        if isinstance(targets, Target):
            targets = [targets]

{'fraction_non_alphanumeric': 0.07173899351262833, 'fraction_numerical': 0.0022674308748504126, 'mean_word_length': 1.8028243601059135, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1497657', 'n_tokens_mistral': 4056, 'n_tokens_neox': 3925, 'n_words': 1447}