def testInvalidScenarios(self): """ Test what happens when a calculator module doesn't exist, or bad parameters are passed in """ badFunction = ScoreFunction(calculator='does.not.Exist', name='bad') self.assertRaises(ImportError, badFunction.score, [self.district1])
def testRangeFunction(self): # create the scoring function for checking if a value passes a range rangeFunction1 = ScoreFunction( calculator='redistricting.calculators.Range', name='RangeFn') rangeFunction1.save() # create the arguments ScoreArgument(function=rangeFunction1, argument='value', value='2', type='literal').save() ScoreArgument(function=rangeFunction1, argument='min', value='1', type='literal').save() ScoreArgument(function=rangeFunction1, argument='max', value='3', type='literal').save() # test raw value score = rangeFunction1.score(self.district1) self.assertEqual(1, score['value'], '2 is between 1 and 3') # HTML score = rangeFunction1.score(self.district1, 'html') self.assertEqual("<span>1</span>", score, 'Range HTML was incorrect: ' + score) # JSON score = rangeFunction1.score(self.district1, 'json') self.assertEqual('{"result": 1}', score, 'Range JSON was incorrect: ' + score)
def testSchwarzbergScoringFunction(self): """ Test the schwarzberg scoring function """ # create the ScoreFunction schwartzFunction = ScoreFunction( calculator='redistricting.calculators.Schwartzberg', name='SchwartzbergFn') # multiple districts scores = schwartzFunction.score([self.district1, self.district2]) self.assertAlmostEquals( 0.86832150547, scores[0]['value'], 9, 'Schwartzberg for first district was incorrect: %f' % scores[0]['value']) self.assertAlmostEquals( 0.88622692545, scores[1]['value'], 9, 'Schwartzberg for second district was incorrect: %f' % scores[1]['value']) # single district as list scores = schwartzFunction.score([self.district1]) self.assertAlmostEquals( 0.86832150547, scores[0]['value'], 9, 'Schwartzberg for District 1 was incorrect: %f' % scores[0]['value']) # single district as object score = schwartzFunction.score(self.district1) self.assertAlmostEquals( 0.86832150547, score['value'], 9, 'Schwartzberg for District 1 was incorrect: %f' % score['value']) # HTML score = schwartzFunction.score(self.district1, 'html') self.assertEqual( "86.8%", score, 'Schwartzberg HTML for District 1 was incorrect: ' + score) # JSON score = json.loads(schwartzFunction.score(self.district1, 'json')) self.assertAlmostEqual( 0.8683215054699209, score['result'], 15, 'Schwartzberg JSON for District 1 was incorrect. (e:"%s", a:"%s")' % ( 0.8683215054699209, score['result'], ))
def testSumPlanFunction(self): """ Test the sum scoring function on a plan level """ # create the scoring function for summing the districts in a plan sumPlanFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumPlanFn', is_planscore=True) sumPlanFunction.save() # create the arguments ScoreArgument(function=sumPlanFunction, argument='value1', value='1', type='literal').save() # test raw value num_districts = len( self.plan.get_districts_at_version(self.plan.version, include_geom=False)) score = sumPlanFunction.score(self.plan) self.assertEqual( num_districts, score['value'], 'sumPlanFunction was incorrect. (e:%d, a:%d)' % (num_districts, score['value'])) # test a list of plans score = sumPlanFunction.score([self.plan, self.plan]) self.assertEqual( num_districts, score[0]['value'], 'sumPlanFunction was incorrect for first plan: %d' % score[0]['value']) self.assertEqual( num_districts, score[1]['value'], 'sumPlanFunction was incorrect for second plan: %d' % score[1]['value'])
def test_splitcounter_display(self): # Create a plan with two districts - one crosses both 5 and 8 p1 = self.plan d1a_id = 1 dist1ids = self.geounits[20:23] + self.geounits[29:32] + \ self.geounits[38:41] + self.geounits[47:50] + \ self.geounits[56:59] dist1ids = map(lambda x: str(x.id), dist1ids) p1.add_geounits(d1a_id, dist1ids, self.geolevel.id, p1.version) # the other is entirely within 5 d2a_id = 5 dist2ids = [self.geounits[32], self.geounits[41], self.geounits[50]] dist2ids = map(lambda x: str(x.id), dist2ids) p1.add_geounits(d2a_id, dist2ids, self.geolevel.id, p1.version) # Get a ScoreDisplay and components to render display = ScoreDisplay.objects.get(title='TestScoreDisplay') display.is_page = False display.save() panel = ScorePanel(title="Splits Report", type="plan", template="sp_template1.html", cssclass="split_panel") function = ScoreFunction( calculator="redistricting.calculators.SplitCounter", name="splits_test", is_planscore=True) geolevel = self.plan.legislative_body.get_geolevels()[0] arg1 = ScoreArgument(argument="boundary_id", value="geolevel.%d" % geolevel.id, type="literal") components = [(panel, [(function, arg1)])] expected_result = ( '%s:[u\'<div class="split_report"><div>Total ' 'districts which split a biggest level short label: 2</div>' '<div>Total number of splits: 7</div>' '<div class="table_container"><table class="report"><thead><tr>' '<th>Testplan</th><th>Biggest level short label</th></tr></thead>' '<tbody><tr><td>District 1</td><td>Unit 1-0</td></tr><tr>' '<td>District 1</td><td>Unit 1-1</td></tr><tr><td>District 1</td>' '<td>Unit 1-3</td></tr><tr><td>District 1</td><td>Unit 1-4</td>' '</tr><tr><td>District 1</td><td>Unit 1-6</td></tr><tr>' '<td>District 1</td><td>Unit 1-7</td></tr><tr><td>District 5</td>' '<td>Unit 1-4</td></tr></tbody></table></div></div>\']') % p1.name tplfile = settings.TEMPLATES[0]['DIRS'][0] + '/' + panel.template template = open(tplfile, 'w') template.write( '{% for planscore in planscores %}{{planscore.plan.name}}:' + '{{ planscore.score|safe }}{% endfor %}') template.close() # Check the result plan_result = display.render(p1, components=components) self.assertEqual( expected_result, plan_result, "Didn't get expected result when rendering " + "SplitCounter:\ne:%s\na:%s" % (expected_result, plan_result)) os.remove(tplfile)
def test_scoredisplay_with_overrides(self): # Get a ScoreDisplay display = ScoreDisplay.objects.get(title='TestScoreDisplay') display.is_page = False # Make up a ScorePanel - don't save it panel = ScorePanel(title="My Fresh Panel", type="district", template="sp_template2.html") # Create two functions, one with an arg and one without function = ScoreFunction( calculator="redistricting.calculators.SumValues", name="My Fresh Calc", is_planscore=False) arg1 = ScoreArgument(argument="value1", value="5", type="literal") arg2 = ScoreArgument(argument="value2", value="TestSubject", type="subject") tplfile = settings.TEMPLATES[0]['DIRS'][0] + '/' + panel.template template = open(tplfile, 'w') template.write('{% for dscore in districtscores %}' + '{{dscore.district.long_label }}:' + '{% for score in dscore.scores %}' + '{{ score.score|safe }}{% endfor %}{% endfor %}') template.close() # Render the ScoreDisplay components = [(panel, [(function, arg1, arg2)])] district_result = display.render([self.district1], components=components) expected = 'District 1:<span>5</span>' self.assertEqual( expected, district_result, 'Didn\'t get expected result when overriding district\'s display ' + '(e:"%s", a:"%s")' % (expected, district_result)) os.remove(tplfile) # Add some districts to our plan geolevelid = self.geolevel.id geounits = self.geounits dist1ids = geounits[0:3] + geounits[9:12] dist2ids = geounits[6:9] + geounits[15:18] dist1ids = map(lambda x: str(x.id), dist1ids) dist2ids = map(lambda x: str(x.id), dist2ids) self.plan.add_geounits(self.district1.district_id, dist1ids, geolevelid, self.plan.version) self.plan.add_geounits(self.district2.district_id, dist2ids, geolevelid, self.plan.version) # Set up the elements to work for a plan panel.type = 'plan' panel.template = 'sp_template1.html' function.is_planscore = True components = [(panel, [(function, arg1, arg2)])] tplfile = settings.TEMPLATES[0]['DIRS'][0] + '/' + panel.template template = open(tplfile, 'w') template.write( '{% for planscore in planscores %}{{planscore.plan.name}}:' + '{{ planscore.score|safe }}{% endfor %}') template.close() # Check the result plan_result = display.render(self.plan, components=components) expected = "testPlan:[u'<span>24</span>']" self.assertEqual( expected, plan_result, 'Didn\'t get expected result when overriding plan\'s display' + ' (e: "%s", a:"%s")' % (expected, plan_result)) os.remove(tplfile)
def testPlanScoreNestedWithDistrictScore(self): """ Test the case where a ScoreFunction of type 'plan' has an argument that is a ScoreFunction of type 'district', in which case, the argument ScoreFunction needs to be evaluated over all districts in the list of plans """ # create the district scoring function for getting subject1 districtSubjectFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='GetSubjectFn') districtSubjectFunction.save() ScoreArgument(function=districtSubjectFunction, argument='value1', value=self.subject1.name, type='subject').save() # create the plan scoring function for summing values planSumFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='PlanSumFn', is_planscore=True) planSumFunction.save() ScoreArgument(function=planSumFunction, value=districtSubjectFunction.name, type='score').save() # subject values are 6, 9, and 0; so the total should be 15 score = planSumFunction.score(self.plan) self.assertEqual( 9, score['value'], 'planSumFunction was incorrect: (e:9, a:%d)' % score['value']) # test a list of plans score = planSumFunction.score([self.plan, self.plan]) self.assertEqual( 9, score[0]['value'], 'planSumFunction was incorrect for first plan: %d' % score[0]['value']) self.assertEqual( 9, score[1]['value'], 'planSumFunction was incorrect for second plan: %d' % score[1]['value']) # test with multiple arguments districtSubjectFunction2 = ScoreFunction( calculator='redistricting.calculators.SumValues', name='GetSubjectFn2') districtSubjectFunction2.save() ScoreArgument(function=districtSubjectFunction2, argument='value1', value=self.subject1.name, type='subject').save() ScoreArgument(function=districtSubjectFunction2, argument='value2', value=self.subject1.name, type='subject').save() planSumFunction2 = ScoreFunction( calculator='redistricting.calculators.SumValues', name='PlanSumFn2', is_planscore=True) planSumFunction2.save() ScoreArgument(function=planSumFunction2, value=districtSubjectFunction2.name, type='score').save() # should be twice as much score = planSumFunction2.score(self.plan) self.assertEqual(18, score['value'], 'planSumFunction was incorrect: %d' % score['value']) # test with adding another argument to the plan function, should # double again ScoreArgument(function=planSumFunction2, value=districtSubjectFunction2.name, type='score').save() score = planSumFunction2.score(self.plan) self.assertEqual(36, score['value'], 'planSumFunction was incorrect: %d' % score['value'])
def testNestedSumPlanFunction(self): """ Test the nested sum scoring function on a plan level """ # create the scoring function for summing the districts in a plan sumPlanFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumPlanFn', is_planscore=True) sumPlanFunction.save() ScoreArgument(function=sumPlanFunction, argument='value1', value='1', type='literal').save() # find the number of districts in the plan in an alternate fashion num_districts = len( self.plan.get_districts_at_version(self.plan.version, include_geom=False)) # ensure the sumPlanFunction works correctly score = sumPlanFunction.score(self.plan) self.assertEqual( num_districts, score['value'], 'sumPlanFunction was incorrect. (e:%d, a:%d)' % ( num_districts, score['value'], )) # create the scoring function for summing the sum of the districts in a # plan sumSumPlanFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumSumPlanFn', is_planscore=True) sumSumPlanFunction.save() ScoreArgument(function=sumSumPlanFunction, argument='value1', value=sumPlanFunction.name, type='score').save() # test nested sum score = sumSumPlanFunction.score(self.plan) self.assertEqual( num_districts**2, score['value'], 'sumSumPlanFunction was incorrect: %d' % score['value']) # test a list of plans score = sumSumPlanFunction.score([self.plan, self.plan]) self.assertEqual( num_districts**2, score[0]['value'], 'sumSumPlanFunction was incorrect for first plan: %d' % score[0]['value']) self.assertEqual( num_districts**2, score[1]['value'], 'sumSumPlanFunction was incorrect for second plan: %d' % score[1]['value'])
def testNestedSumFunction(self): """ Test a sum scoring function that references a sum scoring function """ # create the scoring function for summing two literals sumTwoLiteralsFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumTwoLiteralsFn') sumTwoLiteralsFunction.save() ScoreArgument(function=sumTwoLiteralsFunction, argument='value1', value='5', type='literal').save() ScoreArgument(function=sumTwoLiteralsFunction, argument='value2', value='7', type='literal').save() # create the scoring function for summing a literal and a score sumLiteralAndScoreFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumLiteralAndScoreFn') sumLiteralAndScoreFunction.save() # first argument is just a literal ScoreArgument(function=sumLiteralAndScoreFunction, argument='value1', value='2', type='literal').save() # second argument is a score function ScoreArgument(function=sumLiteralAndScoreFunction, argument='value2', value=sumTwoLiteralsFunction.name, type='score').save() # test nested sum score = sumLiteralAndScoreFunction.score(self.district1) self.assertEqual( 14, score['value'], 'sumLiteralAndScoreFunction was incorrect: %d' % score['value']) # sum two of these nested sums sumTwoNestedSumsFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumTwoNestedSumsFn') sumTwoNestedSumsFunction.save() ScoreArgument(function=sumTwoNestedSumsFunction, argument='value1', value=sumLiteralAndScoreFunction.name, type='score').save() ScoreArgument(function=sumTwoNestedSumsFunction, argument='value2', value=sumLiteralAndScoreFunction.name, type='score').save() score = sumTwoNestedSumsFunction.score(self.district1) self.assertEqual( 28, score['value'], 'sumTwoNestedSumsFunction was incorrect: %d' % score['value']) # test a list of districts score = sumTwoNestedSumsFunction.score( [self.district1, self.district1]) self.assertEqual( 28, score[0]['value'], 'sumTwoNestedSumsFunction was incorrect for first district: %d' % score[0]['value']) self.assertEqual( 28, score[1]['value'], 'sumTwoNestedSumsFunction was incorrect for second district: %d' % score[1]['value'])
def testThresholdFunction(self): # create the scoring function for checking if a value passes a # threshold thresholdFunction1 = ScoreFunction( calculator='redistricting.calculators.Threshold', name='ThresholdFn1') thresholdFunction1.save() # create the arguments ScoreArgument(function=thresholdFunction1, argument='value', value='1', type='literal').save() ScoreArgument(function=thresholdFunction1, argument='threshold', value='2', type='literal').save() # test raw value score = thresholdFunction1.score(self.district1) self.assertEqual(False, score['value'], '1 is not greater than 2') # create a new scoring function to test the inverse thresholdFunction2 = ScoreFunction( calculator='redistricting.calculators.Threshold', name='ThresholdFn2') thresholdFunction2.save() # create the arguments ScoreArgument(function=thresholdFunction2, argument='value', value='2', type='literal').save() ScoreArgument(function=thresholdFunction2, argument='threshold', value='1', type='literal').save() # test raw value score = thresholdFunction2.score(self.district1) self.assertEqual(1, score['value'], '2 is greater than 1') # HTML score = thresholdFunction2.score(self.district1, 'html') self.assertEqual("<span>1</span>", score, 'Threshold HTML was incorrect: ' + score) # JSON score = thresholdFunction2.score(self.district1, 'json') self.assertEqual('{"result": 1}', score, 'Threshold JSON was incorrect: ' + score)
def testSumFunction(self): """ Test the sum scoring function """ # create the scoring function for summing three parameters sumThreeFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumThreeFn') sumThreeFunction.save() # create the arguments ScoreArgument(function=sumThreeFunction, argument='value1', value='0', type='literal').save() ScoreArgument(function=sumThreeFunction, argument='value2', value='1', type='literal').save() ScoreArgument(function=sumThreeFunction, argument='value3', value='2', type='literal').save() # test raw value score = sumThreeFunction.score(self.district1) self.assertEqual(3, score['value'], 'sumThree was incorrect: %d' % score['value']) # HTML -- also make sure mixed case format works score = sumThreeFunction.score(self.district1, 'HtmL') self.assertEqual('<span>3</span>', score, 'sumThree was incorrect: %s' % score) # JSON -- also make sure uppercase format works score = sumThreeFunction.score(self.district1, 'JSON') self.assertEqual('{"result": 3.0}', score, 'sumThree was incorrect: %s' % score) # create the scoring function for summing a literal and a subject sumMixedFunction = ScoreFunction( calculator='redistricting.calculators.SumValues', name='SumMixedFn') sumMixedFunction.save() # create the arguments ScoreArgument(function=sumMixedFunction, argument='value1', value=self.subject1.name, type='subject').save() ScoreArgument(function=sumMixedFunction, argument='value2', value='5.2', type='literal').save() # test raw value score = sumMixedFunction.score(self.district1) self.assertEqual(Decimal('11.2'), score['value'], 'sumMixed was incorrect: %d' % score['value'])