コード例 #1
0
class JsonCaseTestsFile(JsonableMixin):

    """A file of test cases (input and expected output)."""

    meta_attrs = (Attribute('version'),
                  Attribute('rule_set'), )
    data_attrs = (Attribute('test_cases', cls=JsonCaseTestInstance), )
コード例 #2
0
class JsonCaseTestInstance(JsonableMixin):

    """An RCV test case (input and expected output)."""

    meta_attrs = (Attribute('index'),
                  Attribute('rules'), )
    data_attrs = (Attribute('input', cls=JsonCaseContestInput),
                  Attribute('output', cls=JsonCaseTestOutput), )
コード例 #3
0
class JsonCaseBallot(JsonableMixin):

    """The serialization format is a space-delimited string of integers of
    the form: "WEIGHT CHOICE1 CHOICE2 CHOICE3 ...".
    """

    data_attrs = (Attribute('choices'),
                  Attribute('weight'))

    # We need to override model_to_kwargs() since the model object is a
    # tuple rather than a class with attributes.
    @classmethod
    def model_to_kwargs(cls, model_obj):
        """Make jsonable kwargs from the given model object."""
        weight, choices = model_obj
        return {'weight': weight, 'choices': choices}

    def __init__(self, choices=None, weight=1):
        if choices is None:
            choices = ()
        self.choices = tuple(choices)
        self.weight = weight

    def repr_info(self):
        return "weight=%r choices=%r" % (self.weight, self.choices)

    def save_from_model(self, ballot):
        """
        Arguments:
          ballot: a Ballot object.
        """
        try:
            weight, choices = ballot
        except:
            raise Exception("ballot: %r" % ballot)
        self.__init__(choices=choices, weight=weight)

    def to_model(self):
        """
        Arguments:
          ballot: a Ballot object.
        """
        return self.weight, self.choices

    def save_from_jsobj(self, jsobj):
        """Read a JSON object, and set attributes to match."""
        try:
            weight, choices = parse_internal_ballot(jsobj)
        except ValueError:
            # Can happen with "1 2 abc", for example.
            # ValueError: invalid literal for int() with base 10: 'abc'
            raise JsonDeserializeError("error parsing: %r" % jsobj)
        self.__init__(choices=choices, weight=weight)

    def to_jsobj(self):
        """Return a JSON object."""
        ballot = self.to_model()
        return to_internal_ballot(ballot)
コード例 #4
0
class JsonCaseContestInput(JsonableMixin):

    """Contest input for a JSON test case.

    Attributes (metadata):
      normalize_ballots: None means True.  Defaults to None.

    Attributes:
      ballots: an iterable of JsonCaseBallot objects.
      candidate_count: integer number of candidates.
    """

    meta_attrs = (Attribute('id', model=False),
                  Attribute('index', model=False),
                  Attribute('name'),
                  Attribute('normalize_ballots', model=False),
                  Attribute('rule_sets', model=False),
                  Attribute('notes'), )
    data_attrs = (Attribute('ballots', cls=JsonCaseBallot, model=False),
                  Attribute('candidate_count', model=False),
                  # TODO: make model=True.
                  Attribute('tie_elimination_order', model=False), )

    def repr_info(self):
        return "index=%s id=%s" % (self.index, self.id)

    def make_candidate_names(self):
        return contestgen.make_standard_candidate_names(self.candidate_count)

    # TODO: DRY this up by making last two lines part of base class.
    def save_from_model(self, contest):
        """
        Arguments:
          contest: a ContestInput object.
        """
        candidate_count = None if contest.candidates is None else len(contest.candidates)
        with contest.ballots_resource.reading() as ballots:
            ballots = [JsonCaseBallot.from_model(b) for b in ballots]
        kwargs = self.model_to_kwargs(contest)
        self.__init__(candidate_count=candidate_count, ballots=ballots, **kwargs)

    # TODO: think about how the creation of a new ballots resource should
    # be handled, since it involves managing another resource.
    # TODO: DRY this up by making last two lines part of base class.
    def to_model(self):
        """Return a ContestInput object."""
        candidates = self.make_candidate_names()
        ballots = [b.to_model() for b in self.ballots]
        # We use a list resource as the backing store for now because the
        # number of ballots is small.
        resource = streams.ListResource(ballots)
        ballots_resource = models.BallotsResource(resource)
        kwargs = self.model_to_kwargs(self)
        contest = models.ContestInput(candidates=candidates,
                                      ballots_resource=ballots_resource, **kwargs)
        return contest
コード例 #5
0
class JsonCaseRoundResult(JsonableMixin):

    """Represents the results of a round for testing purposes.

    Attributes:
      candidates_info: a CandidatesInfo object.
    """

    data_attrs = (Attribute('candidates_info'),
                  Attribute('elected'),
                  Attribute('eliminated'),
                  Attribute('tie_break'),
                  Attribute('tied_last_place'),
                  Attribute('totals'), )

    # TODO: move this functionality to the base class (and DRY up with related methods).
    def save_attrs_to_jsobj(self, jsobj, names, convert=lambda x: x):
        for name in names:
            value = getattr(self, name)
            if value is None:
                continue
            jsobj[name] = convert(value)

    def numbers_to_names(self, numbers):
        from_number = self.candidates_info.from_number
        return [from_number(n) for n in numbers]

    def totals_to_named_totals(self, totals):
        from_number = self.candidates_info.from_number
        return {from_number(number): total for number, total in totals.items()}

    def to_jsobj(self):
        jsobj = {}
        self.save_attrs_to_jsobj(jsobj, ('tie_break', ))
        self.save_attrs_to_jsobj(jsobj, ('elected', 'eliminated', 'tied_last_place'), self.numbers_to_names)
        self.save_attrs_to_jsobj(jsobj, ('totals', ), self.totals_to_named_totals)
        return jsobj
コード例 #6
0
class JsonCaseConstants(JsonableMixin):

    meta_attrs = (Attribute('name'),
                  Attribute('notes'), )
    data_attrs = (Attribute('candidate_names'), )
コード例 #7
0
class JsonCaseTestOutput(JsonableMixin):

    meta_attrs = ()
    data_attrs = (Attribute('rounds', cls=JsonCaseRoundResult), )
コード例 #8
0
class JsonCaseContestsFile(JsonableMixin):

    """Represents a JSON contests file for open-rcv-tests."""

    meta_attrs = (Attribute('version'), )
    data_attrs = (Attribute('contests', cls=JsonCaseContestInput), )