<commit_before>#!/usr/bin/env python
# -- Content-Encoding: UTF-8 --
"""
Voting engine: Approbation vote

The candidate with the most votes is elected

:author: <NAME>
:copyright: Copyright 2013, isandlaTech
:license: GPLv3
:version: 1.0.0

..

    This file is part of Cohorte.

    Cohorte is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Cohorte 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Cohorte. If not, see <http://www.gnu.org/licenses/>.
"""

# Module version
__version_info__ = (1, 0, 0)
__version__ = ".".join(str(x) for x in __version_info__)

# Documentation strings format
__docformat__ = "restructuredtext en"

# ------------------------------------------------------------------------------

# Voting system
import cohorte.vote

# iPOPO Decorators
from pelix.ipopo.decorators import ComponentFactory, Provides, Instantiate, \
    Property

# Standard library
import logging

# ------------------------------------------------------------------------------

_logger = logging.getLogger(__name__)

# ------------------------------------------------------------------------------

@ComponentFactory()
@Provides(cohorte.vote.SERVICE_VOTE_ENGINE)
@Property('_kind', cohorte.vote.PROP_VOTE_KIND, 'approbation')
@Instantiate('vote-engine-approbation')
class ApprobationEngine(object):
    """
    Voting system core service
    """
    def __init__(self):
        """
        Sets up members
        """
        # Supported kind of vote
        self._kind = None


    def get_kind(self):
        """
        Returns supported kind of vote
        """
        return self._kind


    def get_options(self):
        """
        Returns the options available for this engine

        :return: An option -> description dictionary
        """
        return {"votes_per_elector": "Sets the maximum number of votes for an "
                                     "elector. Default: 1",
                "nb_elected": "Number of candidates to elect. Default: 1"}


    def analyze(self, vote_round, ballots, candidates, parameters, vote_bean):
        """
        Analyzes the results of a vote

        :param vote_round: Round number (starts at 1)
        :param ballots: All ballots of the vote
        :param candidates: List of all candidates
        :param parameters: Parameters for the vote engine
        :param vote_bean: A VoteResults bean
        :return: The candidate(s) with the most votes
        """
        # Get the number of votes to take into account
        nb_votes = parameters.get("votes_per_elector", 1)
        nb_elected = parameters.get("nb_elected", 1)

        # Count the number of votes for each candidate
        results = {}
        for ballot in ballots:
            accepted = ballot.get_for()[:nb_votes]
            for candidate in accepted:
                results[candidate] = results.get(candidate, 0) + 1

        # Store the results, as it makes a sorted list of tuples:
        # (votes, candidate)
        results = vote_bean.set_results(results)

        if nb_elected == 1:
            # Single result
            return results[0][1]
        else:
            # Return the candidates with the most votes
            return tuple(result[1] for result in results[:nb_elected])
<commit_msg>Support for blackbowling in the approbation vote <commit_after>#!/usr/bin/env python
# -- Content-Encoding: UTF-8 --
"""
Voting engine: Approbation vote

The candidate with the most votes is elected

:author: <NAME>
:copyright: Copyright 2013, isandlaTech
:license: GPLv3
:version: 1.0.0

..

    This file is part of Cohorte.

    Cohorte is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Cohorte 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Cohorte. If not, see <http://www.gnu.org/licenses/>.
"""

# Module version
__version_info__ = (1, 0, 0)
__version__ = ".".join(str(x) for x in __version_info__)

# Documentation strings format
__docformat__ = "restructuredtext en"

# ------------------------------------------------------------------------------

# Voting system
import cohorte.vote

# iPOPO Decorators
from pelix.ipopo.decorators import ComponentFactory, Provides, Instantiate, \
    Property

# Standard library
import logging

# ------------------------------------------------------------------------------

_logger = logging.getLogger(__name__)

# ------------------------------------------------------------------------------

@ComponentFactory()
@Provides(cohorte.vote.SERVICE_VOTE_ENGINE)
@Property('_kind', cohorte.vote.PROP_VOTE_KIND, 'approbation')
@Instantiate('vote-engine-approbation')
class ApprobationEngine(object):
    """
    Voting system core service
    """
    def __init__(self):
        """
        Sets up members
        """
        # Supported kind of vote
        self._kind = None


    def get_kind(self):
        """
        Returns supported kind of vote
        """
        return self._kind


    def get_options(self):
        """
        Returns the options available for this engine

        :return: An option -> description dictionary
        """
        return {"votes_per_elector": "Sets the maximum number of votes for an "
                                     "elector. Default: 1",
                "nb_elected": "Number of candidates to elect. Default: 1",
                "penalty": "Penalty implied by a vote against a candidate. "
                           "Default: 0",
                "exclusion": "Number of votes against a candidate before his "
                             "exclusion. Default: 0 (inactive)"}


    def analyze(self, vote_round, ballots, candidates, parameters, vote_bean):
        """
        Analyzes the results of a vote

        :param vote_round: Round number (starts at 1)
        :param ballots: All ballots of the vote
        :param candidates: List of all candidates
        :param parameters: Parameters for the vote engine
        :param vote_bean: A VoteResults bean
        :return: The candidate(s) with the most votes
        """
        # Get the number of votes to take into account
        nb_votes = parameters.get("votes_per_elector", 1)
        nb_elected = parameters.get("nb_elected", 1)
        penalty = parameters.get("penalty", 0)
        penalty_exclusion = parameters.get("exclusion", 0)
        exclusion_value = penalty * (penalty_exclusion + 1)

        # Count the number of votes for each candidate
        results = {}

        nb_penalties = {}
        excluded = []

        for ballot in ballots:
            # Count supported candidates
            for candidate in ballot.get_for()[:nb_votes]:
                results[candidate] = results.get(candidate, 0) + 1

        if penalty > 0 or penalty_exclusion > 0:
            # Exclusion loop
            for ballot in ballots:
                # Count refused candidates
                refused = (candidate
                           for candidate in ballot.get_against()
                           if candidate not in excluded)
                for candidate in refused:
                    # Increase the count of penalties
                    candidate_penalties = results.get(candidate, 0) + 1
                    nb_penalties[candidate] = candidate_penalties

                    if candidate_penalties > penalty_exclusion \
                    and penalty_exclusion > 0:
                        # Candidate is excluded !
                        excluded.append(candidate)
                        results[candidate] = exclusion_value

                    # Add the penalty to the votes
                    if penalty > 0:
                        results[candidate] = results.get(candidate, 0) - penalty

        # Store the results, as it makes a sorted list of tuples:
        # (votes, candidate)
        results = vote_bean.set_results(results)

        if nb_elected == 1:
            # Single result
            return results[0][1]
        else:
            # Return the candidates with the most votes
            return tuple(result[1] for result in results[:nb_elected])

{'fraction_non_alphanumeric': 0.1257981404727232, 'fraction_numerical': 0.006721182928195363, 'mean_word_length': 1.904359141184125, 'pattern_counts': {'":': 6, '<': 7, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6610729', 'n_tokens_mistral': 2368, 'n_tokens_neox': 2203, 'n_words': 826}