<commit_before># This file is part of Fedora Community.
# Copyright (C) 2008-2010  Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import ssl
import time

from datetime import datetime, timedelta
from tg import config
from bugzilla import RHBugzilla3 as Bugzilla

from fedoracommunity.connectors.api import (
    IConnector,
    ICall,
    IQuery,
    ParamFilter,
)
from moksha.common.lib.dates import DateTimeDisplay

import dogpile.cache

# Don't query closed bugs for these packages, since the queries timeout
BLACKLIST = ['kernel']

MAX_BZ_QUERIES = 200
BUG_SORT_KEYS = ['status', 'product', 'version', 'bug_id']

OPEN_BUG_STATUS = ['ASSIGNED', 'NEW', 'MODIFIED', 'ON_DEV', 'ON_QA',
                   'VERIFIED', 'FAILS_QA', 'RELEASE_PENDING', 'POST',
                   'REOPENED']


def chunks(l, n):
    """ Yield successive n-sized chunks from l. """
    for i in xrange(0, len(l), n):
        yield l[i:i + n]


class BugzillaConnector(IConnector, ICall, IQuery):
    _method_paths = {}
    _query_paths = {}

    def __init__(self, environ=None, request=None):
        super(BugzillaConnector, self).__init__(environ, request)
        self.__bugzilla = None

        # Defaults for the dogpile cache
        cache_config = {
            "dogpile.cache.backend": "dogpile.cache.dbm",
            "dogpile.cache.arguments.filename": "dogpile-cache.dbm",
            "dogpile.cache.expiration_time": "300",
        }

        cache_config.update(config)

        # Initialize our dogpile cache.
        self.cache = dogpile.cache.make_region()
        self.cache.configure_from_config(cache_config, "dogpile.cache.")

    @property
    def _bugzilla(self):
        """ A singleton over our python-bugzilla connection. """
        if not self.__bugzilla:
            self.__bugzilla = Bugzilla(
                url=self._base_url,
            )
        return self.__bugzilla

    # IConnector
    @classmethod
    def register(cls):
        cls._base_url = config.get(
            'fedoracommunity.connector.bugzilla.baseurl',
            'https://bugzilla.redhat.com/xmlrpc.cgi')

        cls.register_query_bugs()

        path = cls.register_method('get_bug_stats', cls.query_bug_stats)

    #IQuery
    @classmethod
    def register_query_bugs(cls):
        path = cls.register_query(
            'query_bugs',
            cls.query_bugs,
            primary_key_col='id',
            default_sort_col='date',
            default_sort_order=-1,
            can_paginate=True)

        path.register_column(
            'id',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'status',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'description',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'release',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        f = ParamFilter()
        f.add_filter('package', [], allow_none=False)
        f.add_filter('collection', [], allow_none=False)
        f.add_filter('version', [], allow_none=False)
        cls._query_bugs_filter = f

    def query_bug_stats(self, *args, **kw):
        package = kw.get('package', None)

        if not package:
            raise Exception('No package specified')

        bugzilla_cache = self._request.environ['beaker.cache']\
            .get_cache('bugzilla')
        return bugzilla_cache.get_value(
            key=package,
            expiretime=21600,
            createfunc=lambda: self._get_bug_stats(package),
        )

    def _get_bug_stats(self, package, collection=('Fedora', 'Fedora EPEL')):
        """
        Returns (# of open bugs, # of new bugs, # of closed bugs)
        """
        queries = ['open', 'blockers', 'new_this_week', 'closed_this_week']

        last_week = str(datetime.utcnow() - timedelta(days=7)),

        # Multi-call support is broken in the latest Bugzilla upgrade
        #mc = self._bugzilla._multicall()

        key_prefix = str(package) + "-" + str(collection)
        results = []

        # Open bugs
        def open_bugs():
            return self._bugzilla.query({
                'product': collection,
                'component': package,
                'status': OPEN_BUG_STATUS,
            })
        results.append(self.cache.get_or_create(
            key_prefix + "-open", open_bugs))

        # Blocking Bugs
        blockers = []
        for bug in results[-1]:
            if bug.blocks:
                blockers.append(bug)
        results.append(blockers)

        # Closed Bugs this week
        def closed_bugs():
            return self._bugzilla.query({
                'product': collection,
                'component': package,
                'status': 'CLOSED',
                'creation_time': last_week,
            })
        results.append(self.cache.get_or_create(<commit_msg>Some simplification to the bugzilla connector.<commit_after># This file is part of Fedora Community.
# Copyright (C) 2008-2010  Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import ssl
import time

from datetime import datetime, timedelta
from tg import config
from bugzilla import RHBugzilla3 as Bugzilla

from fedoracommunity.connectors.api import (
    IConnector,
    ICall,
    IQuery,
    ParamFilter,
)
from moksha.common.lib.dates import DateTimeDisplay

import dogpile.cache

# Don't query closed bugs for these packages, since the queries timeout
BLACKLIST = ['kernel']

MAX_BZ_QUERIES = 200
BUG_SORT_KEYS = ['status', 'product', 'version', 'bug_id']

OPEN_BUG_STATUS = ['ASSIGNED', 'NEW', 'MODIFIED', 'ON_DEV', 'ON_QA',
                   'VERIFIED', 'FAILS_QA', 'RELEASE_PENDING', 'POST',
                   'REOPENED']


def chunks(l, n):
    """ Yield successive n-sized chunks from l. """
    for i in xrange(0, len(l), n):
        yield l[i:i + n]


class BugzillaConnector(IConnector, ICall, IQuery):
    _method_paths = {}
    _query_paths = {}

    def __init__(self, environ=None, request=None):
        super(BugzillaConnector, self).__init__(environ, request)
        self.__bugzilla = None

        # Defaults for the dogpile cache
        cache_config = {
            "dogpile.cache.backend": "dogpile.cache.dbm",
            "dogpile.cache.arguments.filename": "dogpile-cache.dbm",
            "dogpile.cache.expiration_time": "300",
        }

        cache_config.update(config)

        # Initialize our dogpile cache.
        self.cache = dogpile.cache.make_region()
        self.cache.configure_from_config(cache_config, "dogpile.cache.")

    @property
    def _bugzilla(self):
        """ A singleton over our python-bugzilla connection. """
        if not self.__bugzilla:
            self.__bugzilla = Bugzilla(
                url=self._base_url,
            )
        return self.__bugzilla

    # IConnector
    @classmethod
    def register(cls):
        cls._base_url = config.get(
            'fedoracommunity.connector.bugzilla.baseurl',
            'https://bugzilla.redhat.com/xmlrpc.cgi')

        cls.register_query_bugs()

        path = cls.register_method('get_bug_stats', cls.query_bug_stats)

    #IQuery
    @classmethod
    def register_query_bugs(cls):
        path = cls.register_query(
            'query_bugs',
            cls.query_bugs,
            primary_key_col='id',
            default_sort_col='date',
            default_sort_order=-1,
            can_paginate=True)

        path.register_column(
            'id',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'status',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'description',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        path.register_column(
            'release',
            default_visible=True,
            can_sort=True,
            can_filter_wildcards=False)

        f = ParamFilter()
        f.add_filter('package', [], allow_none=False)
        f.add_filter('collection', [], allow_none=False)
        f.add_filter('version', [], allow_none=False)
        cls._query_bugs_filter = f

    def query_bug_stats(self, path, cookies, package=None, **kw):
        """
        Returns (# of open bugs, # of new bugs, # of closed bugs)

        Registered with the fcomm_connector middleware as get_bug_stats..
        which is non-obvious and confusing.
        """

        if not package:
            raise Exception('No package specified')

        collection = ('Fedora', 'Fedora EPEL')

        queries = ['open', 'blockers', 'new_this_week', 'closed_this_week']

        last_week = str(datetime.utcnow() - timedelta(days=7)),

        # Multi-call support is broken in the latest Bugzilla upgrade
        #mc = self._bugzilla._multicall()

        key_prefix = str(package) + "-" + str(collection)
        results = []

        # Open bugs
        def open_bugs():
            return self._bugzilla.query({
                'product': collection,
                'component': package,
                'status': OPEN_BUG_STATUS,
            })
        results.append(self.cache.get_or_create(
            key_prefix + "-open", open_bugs))

        # Blocking Bugs
        blocker_bugs = lambda: [bug for bug in results[-1] if bug.blocks]
        results.append(self.cache.get_or_create(
            key_prefix + "-block", blocker_bugs))

        # Closed Bugs this week
        def closed_bugs():
            return self._bugzilla.query({
                'product': collection,
                'component': package,
                'status': 'CLOSED',
                'creation_time': last_week,
            })
        results.append(self.cache.get_or_create(
{'fraction_non_alphanumeric': 0.10083215297450425, 'fraction_numerical': 0.00398371104815864, 'mean_word_length': 2.270700636942675, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, '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': '1683405', 'n_tokens_mistral': 3403, 'n_tokens_neox': 3215, 'n_words': 828}