<commit_before>from feedly.feeds.aggregated_feed import AggregatedFeed
from feedly.serializers.aggregated_activity_serializer import \
    AggregatedActivitySerializer
from feedly.structures.sorted_set import RedisSortedSetCache
import copy
import datetime
import logging

logger = logging.getLogger(__name__)


class NotificationFeed(AggregatedFeed):
    '''
    Similar to an aggregated feed, but adds
    - denormalized counts
    - pubsub signals
    '''
    serializer_class = AggregatedActivitySerializer

    max_length = 99
    # key format for storing the sorted set
    key_format = 'notification_feed:1:user:%s'
    # the format we use to denormalize the count
    count_format = 'notification_feed:1:user:%(user_id)s:count'
    # the format we use to send the pubsub update
    pubsub_format = 'notification_feed:1:user:%(user_id)s:pubsub'

    def __init__(self, user_id, redis=None):
        '''
        User id (the user for which we want to read/write notifications)
        '''
        AggregatedFeed.__init__(self, user_id, redis=redis)
        # location to which we denormalize the count
        self.count_key = self.count_format % self.format_dict
        # set the pubsub key if we're using it
        pubsub_format = getattr(self, 'pubsub_format', None)
        pubsub_key = None
        if pubsub_format:
            pubsub_key = self.pubsub_format % self.format_dict
        self.pubsub_key = pubsub_key

    def add_many(self, activities):
        current_activities = AggregatedFeed.add_many(self, activities)
        # denormalize the count
        count = self.denormalize_count(current_activities)
        # send a pubsub request
        if self.pubsub_key:
            publish_result = self.redis.publish(self.pubsub_key, count)

        # return the current state of the notification feed
        return current_activities

    def get_denormalized_count(self):
        '''
        Returns the denormalized count stored in self.count_key
        '''
        result = self.redis.get(self.count_key)
        result = int(result)
        return result

    def denormalize_count(self, activities):
        '''
        Denormalize the number of unseen aggregated activities to the key
        defined in self.count_key
        '''
        activities.sort(key=lambda x: x.last_seen, reverse=True)
        current_activities = activities[:self.max_length]
        count = self.count_unseen(current_activities)
        logger.debug('denormalizing count %s', count)
        self.redis.set(self.count_key, count)
        # send a pubsub request
        if self.pubsub_key:
            publish_result = self.redis.publish(self.pubsub_key, count)

        return count

    def count_unseen(self, activities=None):
        '''
        Counts the number of aggregated activities which are unseen<commit_msg>fix cast None to int<commit_after>from feedly.feeds.aggregated_feed import AggregatedFeed
from feedly.serializers.aggregated_activity_serializer import \
    AggregatedActivitySerializer
from feedly.structures.sorted_set import RedisSortedSetCache
import copy
import datetime
import logging

logger = logging.getLogger(__name__)


class NotificationFeed(AggregatedFeed):
    '''
    Similar to an aggregated feed, but adds
    - denormalized counts
    - pubsub signals
    '''
    serializer_class = AggregatedActivitySerializer

    max_length = 99
    # key format for storing the sorted set
    key_format = 'notification_feed:1:user:%s'
    # the format we use to denormalize the count
    count_format = 'notification_feed:1:user:%(user_id)s:count'
    # the format we use to send the pubsub update
    pubsub_format = 'notification_feed:1:user:%(user_id)s:pubsub'

    def __init__(self, user_id, redis=None):
        '''
        User id (the user for which we want to read/write notifications)
        '''
        AggregatedFeed.__init__(self, user_id, redis=redis)
        # location to which we denormalize the count
        self.count_key = self.count_format % self.format_dict
        # set the pubsub key if we're using it
        pubsub_format = getattr(self, 'pubsub_format', None)
        pubsub_key = None
        if pubsub_format:
            pubsub_key = self.pubsub_format % self.format_dict
        self.pubsub_key = pubsub_key

    def add_many(self, activities):
        current_activities = AggregatedFeed.add_many(self, activities)
        # denormalize the count
        count = self.denormalize_count(current_activities)
        # send a pubsub request
        if self.pubsub_key:
            publish_result = self.redis.publish(self.pubsub_key, count)

        # return the current state of the notification feed
        return current_activities

    def get_denormalized_count(self):
        '''
        Returns the denormalized count stored in self.count_key
        '''
        result = self.redis.get(self.count_key) or 0
        result = int(result)
        return result

    def denormalize_count(self, activities):
        '''
        Denormalize the number of unseen aggregated activities to the key
        defined in self.count_key
        '''
        activities.sort(key=lambda x: x.last_seen, reverse=True)
        current_activities = activities[:self.max_length]
        count = self.count_unseen(current_activities)
        logger.debug('denormalizing count %s', count)
        self.redis.set(self.count_key, count)
        # send a pubsub request
        if self.pubsub_key:
            publish_result = self.redis.publish(self.pubsub_key, count)

        return count

    def count_unseen(self, activities=None):
        '''
        Counts the number of aggregated activities which are unseen
{'fraction_non_alphanumeric': 0.07233592095977417, 'fraction_numerical': 0.0019407198306280876, 'mean_word_length': 2.9015829318651067, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6867011', 'n_tokens_mistral': 1646, 'n_tokens_neox': 1602, 'n_words': 433}