diff --git a/apportionment/examples/alldifferent.py b/apportionment/examples/alldifferent.py index ba7d36f..ef91209 100644 --- a/apportionment/examples/alldifferent.py +++ b/apportionment/examples/alldifferent.py @@ -13,7 +13,7 @@ seats = 20 methods = ["quota", "largest_remainder", "dhondt", "saintelague", "adams"] -iterator = combinations(range(1, maxvoters+1), parties) +iterator = combinations(range(1, maxvoters + 1), parties) for iterations, votes in enumerate(iterator): apportionments = set() @@ -21,8 +21,10 @@ for iterations, votes in enumerate(iterator): for method in methods: try: # in case of ties an exception occurs because tiesallowed=False apportionments.add( - tuple(app.compute(method, votes, seats, - tiesallowed=False, verbose=False))) + tuple( + app.compute(method, votes, seats, tiesallowed=False, verbose=False) + ) + ) except Exception: pass @@ -36,6 +38,6 @@ print("votes = {}".format(votes)) print("found in {} iterations\n\n".format(iterations)) for method in methods: - print("{:>20s}: {}".format(method, - app.compute(method, votes, seats, - verbose=False))) + print( + "{:>20s}: {}".format(method, app.compute(method, votes, seats, verbose=False)) + ) diff --git a/apportionment/examples/austria.py b/apportionment/examples/austria.py index 3914526..ccfeb45 100644 --- a/apportionment/examples/austria.py +++ b/apportionment/examples/austria.py @@ -7,12 +7,12 @@ with open("./nr_wahlen.txt", "r") as f: for line in f: year, partynames, votes, officialresult = eval(line) print(year) - result = app.compute("dhondt", votes, - 183, - parties=partynames, - threshold=.04, - verbose=True) + result = app.compute( + "dhondt", votes, 183, parties=partynames, threshold=0.04, verbose=True + ) # actual results - print("Identical with official result: " - + (str(tuple(result) == tuple(officialresult))) - + "\n\n") + print( + "Identical with official result: " + + (str(tuple(result) == tuple(officialresult))) + + "\n\n" + ) diff --git a/apportionment/examples/israel.py b/apportionment/examples/israel.py index 1229770..62ff796 100644 --- a/apportionment/examples/israel.py +++ b/apportionment/examples/israel.py @@ -8,15 +8,19 @@ print("See https://www.knesset.gov.il/lexicon/eng/seats_eng.htm\n") with open("knesset.txt", "r") as f: for line in f: - knesset_nr, partynames, votes, officialresult, threshold = \ - eval(line) + knesset_nr, partynames, votes, officialresult, threshold = eval(line) print("Knesset #" + str(knesset_nr) + ":") - result = app.compute("dhondt", votes, - sum(officialresult), - parties=partynames, - threshold=threshold, - verbose=True) + result = app.compute( + "dhondt", + votes, + sum(officialresult), + parties=partynames, + threshold=threshold, + verbose=True, + ) # actual results - print("Identical with official result: " - + (str(tuple(result) == tuple(officialresult))) - + "\n\n") + print( + "Identical with official result: " + + (str(tuple(result) == tuple(officialresult))) + + "\n\n" + ) diff --git a/apportionment/examples/simple.py b/apportionment/examples/simple.py index 6d452c1..2d0e594 100644 --- a/apportionment/examples/simple.py +++ b/apportionment/examples/simple.py @@ -4,12 +4,19 @@ import apportionment.methods as app votes = [1, 3, 6, 7, 78] seats = 20 -print("votes", "."*(25 - len("votes")), votes, "\n") +print("votes", "." * (25 - len("votes")), votes, "\n") print(seats, "seats", "\n") print("apportionment results:") -for method in ["quota", "largest_remainder", "dhondt", - "saintelague", "huntington", "adams", "dean"]: +for method in [ + "quota", + "largest_remainder", + "dhondt", + "saintelague", + "huntington", + "adams", + "dean", +]: result = app.compute(method, votes, seats, verbose=False) - print(method, "."*(25 - len(method)), result) + print(method, "." * (25 - len(method)), result) diff --git a/apportionment/methods.py b/apportionment/methods.py index 3dbe796..b875593 100644 --- a/apportionment/methods.py +++ b/apportionment/methods.py @@ -7,32 +7,55 @@ import math from fractions import Fraction -METHODS = ["quota", "largest_remainder", "dhondt", "saintelague", - "modified_saintelague", "huntington", "adams", "dean"] +METHODS = [ + "quota", + "largest_remainder", + "dhondt", + "saintelague", + "modified_saintelague", + "huntington", + "adams", + "dean", +] class TiesException(Exception): pass -def compute(method, votes, seats, parties=string.ascii_letters, - threshold=None, tiesallowed=True, verbose=True): +def compute( + method, + votes, + seats, + parties=string.ascii_letters, + threshold=None, + tiesallowed=True, + verbose=True, +): filtered_votes = apply_threshold(votes, threshold) if method == "quota": return quota(filtered_votes, seats, parties, tiesallowed, verbose) elif method in ["lrm", "hamilton", "largest_remainder"]: - return largest_remainder(filtered_votes, seats, parties, - tiesallowed, verbose) - elif method in ["dhondt", "jefferson", "saintelague", "webster", - "modified_saintelague", - "huntington", "hill", "adams", "dean", - "smallestdivisor", "harmonicmean", "equalproportions", - "majorfractions", "greatestdivisors"]: - return divisor(filtered_votes, seats, method, parties, - tiesallowed, verbose) + return largest_remainder(filtered_votes, seats, parties, tiesallowed, verbose) + elif method in [ + "dhondt", + "jefferson", + "saintelague", + "webster", + "modified_saintelague", + "huntington", + "hill", + "adams", + "dean", + "smallestdivisor", + "harmonicmean", + "equalproportions", + "majorfractions", + "greatestdivisors", + ]: + return divisor(filtered_votes, seats, method, parties, tiesallowed, verbose) else: - raise NotImplementedError("apportionment method " + method + - " not known") + raise NotImplementedError("apportionment method " + method + " not known") def apply_threshold(votes, threshold): @@ -52,14 +75,14 @@ def apply_threshold(votes, threshold): def __print_results(representatives, parties): + print("apportionment:") for i in range(len(representatives)): - print(" "+str(parties[i])+": "+str(representatives[i])) + print(" " + str(parties[i]) + ": " + str(representatives[i])) # verifies whether a given assignment of representatives # is within quota -def within_quota(votes, representatives, parties=string.ascii_letters, - verbose=True): +def within_quota(votes, representatives, parties=string.ascii_letters, verbose=True): n = sum(votes) seats = sum(representatives) within = True @@ -67,36 +90,51 @@ def within_quota(votes, representatives, parties=string.ascii_letters, upperquota = int(math.ceil(float(votes[i]) * seats / n)) if representatives[i] > upperquota: if verbose: - print("upper quota of party", parties[i], - "violated: quota is", float(votes[i]) * seats / n, - "but has", representatives[i], "representatives") + print( + "upper quota of party", + parties[i], + "violated: quota is", + float(votes[i]) * seats / n, + "but has", + representatives[i], + "representatives", + ) within = False lowerquota = int(math.floor(float(votes[i]) * seats / n)) if representatives[i] < lowerquota: if verbose: - print("lower quota of party", parties[i], - "violated: quota is", float(votes[i]) * seats / n, - "but has only", representatives[i], "representatives") + print( + "lower quota of party", + parties[i], + "violated: quota is", + float(votes[i]) * seats / n, + "but has only", + representatives[i], + "representatives", + ) within = False return within # Largest remainder method (Hamilton method) -def largest_remainder(votes, seats, parties=string.ascii_letters, - tiesallowed=True, verbose=True): +def largest_remainder( + votes, seats, parties=string.ascii_letters, tiesallowed=True, verbose=True +): if verbose: print("\nLargest remainder method with Hare quota (Hamilton)") q = Fraction(sum(votes), seats) quotas = [Fraction(p, q) for p in votes] - representatives = [int(qu.numerator)//int(qu.denominator) for qu in quotas] + representatives = [int(qu.numerator) // int(qu.denominator) for qu in quotas] ties = False if sum(representatives) < seats: - remainders = [a-b for a, b in zip(quotas, representatives)] - cutoff = sorted(remainders, reverse=True)[seats-sum(representatives)-1] - tiebreaking_message = (" tiebreaking in order of: " + - str(parties[:len(votes)]) + - "\n ties broken in favor of: ") + remainders = [a - b for a, b in zip(quotas, representatives)] + cutoff = sorted(remainders, reverse=True)[seats - sum(representatives) - 1] + tiebreaking_message = ( + " tiebreaking in order of: " + + str(parties[: len(votes)]) + + "\n ties broken in favor of: " + ) for i in range(len(votes)): if sum(representatives) == seats and remainders[i] >= cutoff: if not ties: @@ -122,49 +160,54 @@ def largest_remainder(votes, seats, parties=string.ascii_letters, # Divisor methods -def divisor(votes, seats, method, parties=string.ascii_letters, - tiesallowed=True, verbose=True): +def divisor( + votes, seats, method, parties=string.ascii_letters, tiesallowed=True, verbose=True +): representatives = [0] * len(votes) if method in ["dhondt", "jefferson", "greatestdivisors"]: if verbose: print("\nD'Hondt (Jefferson) method") - divisors = [i+1 for i in range(seats)] + divisors = [i + 1 for i in range(seats)] elif method in ["saintelague", "webster", "majorfractions"]: if verbose: print("\nSainte Lague (Webster) method") - divisors = [2*i+1 for i in range(seats)] + divisors = [2 * i + 1 for i in range(seats)] elif method in ["modified_saintelague"]: if verbose: print("\nModified Sainte Lague (Webster) method") - divisors = [1.4] + [2*i+1 for i in range(1, seats)] + divisors = [1.4] + [2 * i + 1 for i in range(1, seats)] elif method in ["huntington", "hill", "equalproportions"]: if verbose: print("\nHuntington-Hill method") if seats < len(votes): representatives = __divzero_fewerseatsthanparties( - votes, seats, parties, tiesallowed, verbose) + votes, seats, parties, tiesallowed, verbose + ) else: representatives = [1 if p > 0 else 0 for p in votes] - divisors = [math.sqrt((i+1)*(i+2)) for i in range(seats)] + divisors = [math.sqrt((i + 1) * (i + 2)) for i in range(seats)] elif method in ["adams", "smallestdivisor"]: if verbose: print("\nAdams method") if seats < len(votes): representatives = __divzero_fewerseatsthanparties( - votes, seats, parties, tiesallowed, verbose) + votes, seats, parties, tiesallowed, verbose + ) else: representatives = [1 if p > 0 else 0 for p in votes] - divisors = [i+1 for i in range(seats)] + divisors = [i + 1 for i in range(seats)] elif method in ["dean", "harmonicmean"]: if verbose: print("\nDean method") if seats < len(votes): representatives = __divzero_fewerseatsthanparties( - votes, seats, parties, tiesallowed, verbose) + votes, seats, parties, tiesallowed, verbose + ) else: representatives = [1 if p > 0 else 0 for p in votes] - divisors = [Fraction(2 * (i+1) * (i+2), 2 * (i+1) + 1) - for i in range(seats)] + divisors = [ + Fraction(2 * (i + 1) * (i + 2), 2 * (i + 1) + 1) for i in range(seats) + ] else: raise NotImplementedError("divisor method " + method + " not known") @@ -185,9 +228,11 @@ def divisor(votes, seats, method, parties=string.ascii_letters, ties = False # dealing with ties if seats > sum(representatives): - tiebreaking_message = (" tiebreaking in order of: " + - str(parties[:len(votes)]) + - "\n ties broken in favor of: ") + tiebreaking_message = ( + " tiebreaking in order of: " + + str(parties[: len(votes)]) + + "\n ties broken in favor of: " + ) for i in range(len(votes)): if sum(representatives) == seats and minweight in weights[i]: if not ties: @@ -213,15 +258,17 @@ def divisor(votes, seats, method, parties=string.ascii_letters, # required for methods with 0 divisors (Adams, Huntington-Hill) -def __divzero_fewerseatsthanparties(votes, seats, parties, - tiesallowed, verbose): +def __divzero_fewerseatsthanparties(votes, seats, parties, tiesallowed, verbose): representatives = [0] * len(votes) if verbose: - print(" fewer seats than parties; " + str(seats) + - " strongest parties receive one seat") + print( + " fewer seats than parties; " + + str(seats) + + " strongest parties receive one seat" + ) tiebreaking_message = " ties broken in favor of: " ties = False - mincount = sorted(votes, reverse=True)[seats-1] + mincount = sorted(votes, reverse=True)[seats - 1] for i in range(len(votes)): if sum(representatives) < seats and votes[i] >= mincount: if votes[i] == mincount: @@ -240,54 +287,52 @@ def __divzero_fewerseatsthanparties(votes, seats, parties, return representatives -# The quota method -# ( see Balinski, M. L., & Young, H. P. (1975). -# The quota method of apportionment. -# The American Mathematical Monthly, 82(7), 701-730.) -def quota(votes, seats, parties=string.ascii_letters, - tiesallowed=True, verbose=True): +def quota(votes, seats, parties=string.ascii_letters, tiesallowed=True, verbose=True): + """The quota method + see Balinski, M. L., & Young, H. P. (1975). + The quota method of apportionment. + The American Mathematical Monthly, 82(7), 701-730.) + + Warning: tiesallowed is not supported here (difficult to implement) + """ + if not tiesallowed: + raise NotImplementedError( + "parameter tiesallowed not supported for Quota method" + ) if verbose: print("\nQuota method") representatives = [0] * len(votes) while sum(representatives) < seats: - quotas = [Fraction(votes[i], representatives[i]+1) - for i in range(len(votes))] + quotas = [Fraction(votes[i], representatives[i] + 1) for i in range(len(votes))] # check if upper quota is violated for i in range(len(votes)): - upperquota = int(math.ceil(float(votes[i]) * - (sum(representatives)+1) - / sum(votes))) + upperquota = int( + math.ceil(float(votes[i]) * (sum(representatives) + 1) / sum(votes)) + ) if representatives[i] >= upperquota: quotas[i] = 0 - maxquotas = [i for i in range(len(votes)) - if quotas[i] == max(quotas)] + maxquotas = [i for i in range(len(votes)) if quotas[i] == max(quotas)] nextrep = maxquotas[0] + + # print tiebreaking information + if verbose and len(maxquotas) > 1: + print( + "tiebreaking necessary in round " + + str(sum(representatives) + 1) + + ":" + + " tiebreaking in order of: " + + str(parties[: len(votes)]) + + "\n ties broken in favor of: " + + str(parties[nextrep]) + + "\n to the disadvantage of: " + + ", ".join(parties[i] for i in maxquotas[1:]) + ) + representatives[nextrep] += 1 - if len(maxquotas) > 1 and not tiesallowed: - raise TiesException("Tie occurred") - - # print tiebreaking information - if verbose and len(maxquotas) > 1: - quotas_now = [Fraction(votes[i], representatives[i]+1) - for i in range(len(votes))] - tiebreaking_message = (" tiebreaking in order of: " + - str(parties[:len(votes)]) + - "\n ties broken in favor of: ") - ties_favor = [i for i in range(len(votes)) - if quotas_now[i] == quotas_now[nextrep]] - for i in ties_favor: - tiebreaking_message += str(parties[i]) + ", " - tiebreaking_message = (tiebreaking_message[:-2] + - "\n to the disadvantage of: ") - for i in maxquotas[1:]: - tiebreaking_message += str(parties[i]) + ", " - print(tiebreaking_message[:-2]) - if verbose: __print_results(representatives, parties) return representatives - \ No newline at end of file diff --git a/apportionment/unittests.py b/apportionment/unittests.py index e81f86e..847c367 100644 --- a/apportionment/unittests.py +++ b/apportionment/unittests.py @@ -6,22 +6,33 @@ import apportionment.methods as app class TestApprovalMultiwinner(unittest.TestCase): - def test_all_implemented(self): - ALLMETHODSSTRINGS = ["quota", "lrm", "hamilton", "largest_remainder", - "dhondt", "jefferson", "saintelague", "webster", - "huntington", "hill", "adams", "dean", - "smallestdivisor", "harmonicmean", - "equalproportions", "majorfractions", - "greatestdivisors", "modified_saintelague"] + ALLMETHODSSTRINGS = [ + "quota", + "lrm", + "hamilton", + "largest_remainder", + "dhondt", + "jefferson", + "saintelague", + "webster", + "huntington", + "hill", + "adams", + "dean", + "smallestdivisor", + "harmonicmean", + "equalproportions", + "majorfractions", + "greatestdivisors", + "modified_saintelague", + ] votes = [1] seats = 1 for method in ALLMETHODSSTRINGS: - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, [1], - msg=method + " does not exist") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, [1], msg=method + " does not exist") def test_weak_proportionality(self): self.longMessage = True @@ -29,10 +40,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [14, 28, 7, 35] seats = 12 for method in app.METHODS: - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, [2, 4, 1, 5], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, [2, 4, 1, 5], msg=method + " failed") def test_zero_parties(self): self.longMessage = True @@ -40,10 +49,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [0, 14, 28, 0, 0] seats = 6 for method in app.METHODS: - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, [0, 2, 4, 0, 0], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, [0, 2, 4, 0, 0], msg=method + " failed") def test_fewerseatsthanparties(self): self.longMessage = True @@ -51,10 +58,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [10, 9, 8, 8, 11, 12] seats = 3 for method in app.METHODS: - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, [1, 0, 0, 0, 1, 1], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, [1, 0, 0, 0, 1, 1], msg=method + " failed") # examples taken from # Balinski, M. L., & Young, H. P. (1975). @@ -63,44 +68,42 @@ class TestApprovalMultiwinner(unittest.TestCase): def test_balinski_young_example1(self): self.longMessage = True - RESULTS = {"quota": [52, 44, 2, 1, 1], - "largest_remainder": [51, 44, 2, 2, 1], - "dhondt": [52, 45, 1, 1, 1], - "saintelague": [51, 43, 2, 2, 2], - "modified_saintelague": [51, 43, 2, 2, 2], - "huntington": [51, 43, 2, 2, 2], - "adams": [51, 43, 2, 2, 2], - "dean": [51, 43, 2, 2, 2] - } + RESULTS = { + "quota": [52, 44, 2, 1, 1], + "largest_remainder": [51, 44, 2, 2, 1], + "dhondt": [52, 45, 1, 1, 1], + "saintelague": [51, 43, 2, 2, 2], + "modified_saintelague": [51, 43, 2, 2, 2], + "huntington": [51, 43, 2, 2, 2], + "adams": [51, 43, 2, 2, 2], + "dean": [51, 43, 2, 2, 2], + } votes = [5117, 4400, 162, 161, 160] seats = 100 for method in RESULTS.keys(): - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, RESULTS[method], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, RESULTS[method], msg=method + " failed") def test_balinski_young_example2(self): self.longMessage = True - RESULTS = {"quota": [10, 7, 5, 3, 1], - "largest_remainder": [9, 7, 5, 4, 1], - "dhondt": [10, 7, 5, 3, 1], - "saintelague": [9, 8, 5, 3, 1], - "modified_saintelague": [9, 8, 5, 3, 1], - "huntington": [9, 7, 6, 3, 1], - "adams": [9, 7, 5, 3, 2], - "dean": [9, 7, 5, 4, 1] - } + RESULTS = { + "quota": [10, 7, 5, 3, 1], + "largest_remainder": [9, 7, 5, 4, 1], + "dhondt": [10, 7, 5, 3, 1], + "saintelague": [9, 8, 5, 3, 1], + "modified_saintelague": [9, 8, 5, 3, 1], + "huntington": [9, 7, 6, 3, 1], + "adams": [9, 7, 5, 3, 2], + "dean": [9, 7, 5, 4, 1], + } votes = [9061, 7179, 5259, 3319, 1182] seats = 26 for method in RESULTS.keys(): - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, RESULTS[method], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, RESULTS[method], msg=method + " failed") def test_tiebreaking(self): self.longMessage = True @@ -108,78 +111,80 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [2, 1, 1, 2, 2] seats = 2 for method in app.METHODS: - result = app.compute(method, votes, - seats, verbose=False) - self.assertEqual(result, [1, 0, 0, 1, 0], - msg=method + " failed") + result = app.compute(method, votes, seats, verbose=False) + self.assertEqual(result, [1, 0, 0, 1, 0], msg=method + " failed") def test_within_quota(self): votes = [5117, 4400, 162, 161, 160] representatives = [51, 44, 2, 2, 1] - self.assertTrue(app.within_quota(votes, representatives, - verbose=False)) + self.assertTrue(app.within_quota(votes, representatives, verbose=False)) representatives = [52, 45, 1, 1, 1] - self.assertFalse(app.within_quota(votes, representatives, - verbose=False)) + self.assertFalse(app.within_quota(votes, representatives, verbose=False)) representatives = [52, 43, 2, 1, 2] - self.assertFalse(app.within_quota(votes, representatives, - verbose=False)) + self.assertFalse(app.within_quota(votes, representatives, verbose=False)) def test_threshold(self): votes = [41, 56, 3] seats = 60 threshold = 0.03 filtered_votes = app.apply_threshold(votes, threshold) - self.assertEqual(filtered_votes, [41, 56, 3], - "Threshold cut too much.") + self.assertEqual(filtered_votes, [41, 56, 3], "Threshold cut too much.") threshold = 0.031 filtered_votes = app.apply_threshold(votes, threshold) - self.assertEqual(filtered_votes, [41, 56, 0], - "Threshold was not applied correctly.") + self.assertEqual( + filtered_votes, [41, 56, 0], "Threshold was not applied correctly." + ) method = "dhondt" threshold = 0 - unfiltered_result = app.compute(method, votes, seats, - threshold=threshold, - verbose=False) + unfiltered_result = app.compute( + method, votes, seats, threshold=threshold, verbose=False + ) threshold = 0.04 - filtered_result = app.compute(method, votes, seats, - threshold=threshold, - verbose=False) - self.assertNotEqual(unfiltered_result, filtered_result, - "Result did not change despite threshold") + filtered_result = app.compute( + method, votes, seats, threshold=threshold, verbose=False + ) + self.assertNotEqual( + unfiltered_result, + filtered_result, + "Result did not change despite threshold", + ) def test_saintelague_difference(self): votes = [6, 1] seats = 4 - r1 = app.compute("saintelague", votes, - seats, verbose=False) # [3, 1] - r2 = app.compute("modified_saintelague", votes, - seats, verbose=False) # [4, 0] - self.assertNotEqual(r1, r2, - "Sainte Lague and its modified variant" - + "should produce different results.") + r1 = app.compute("saintelague", votes, seats, verbose=False) # [3, 1] + r2 = app.compute("modified_saintelague", votes, seats, verbose=False) # [4, 0] + self.assertNotEqual( + r1, + r2, + "Sainte Lague and its modified variant" + + "should produce different results.", + ) def test_no_ties_allowed(self): self.longMessage = True votes = [11, 11, 11] seats = 4 for method in app.METHODS: - with self.assertRaises(app.TiesException, - msg=method + " failed"): - app.compute(method, votes, seats, - tiesallowed=False, verbose=False) + if method == "quota": + continue + with self.assertRaises(app.TiesException, msg=method + " failed"): + app.compute(method, votes, seats, tiesallowed=False, verbose=False) def test_no_ties_allowed2(self): self.longMessage = True votes = [12, 12, 11, 12] seats = 3 for method in app.METHODS: + if method == "quota": + continue self.assertEqual( - app.compute(method, votes, seats, - tiesallowed=False, verbose=False), - [1, 1, 0, 1], msg=method + " failed") + app.compute(method, votes, seats, tiesallowed=False, verbose=False), + [1, 1, 0, 1], + msg=method + " failed", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main()