def test_place_is_required(self): """ Some job titles (like an MP) are meaningless if there is no place associated with them. """ # create position with no place position = models.Position( person=self.person, title=self.title, ) position._set_sorting_dates() position.full_clean() # Change the title to require a place self.title.requires_place = True with self.assertRaises(exceptions.ValidationError): position.full_clean() # give the pos a place and check that it now validates position.place = models.Place(name='Test Place', slug='test-place') position.full_clean() # put it back self.title.requires_place = False
def test_display_dates(self): """Check that the date that is displayed is correct""" position = models.Position(person=self.person) # Dates that will be used for testing past = ApproximateDate(past=True) y2000 = ApproximateDate(year=2000) y2100 = ApproximateDate(year=2100) future = ApproximateDate(future=True) # test grid: start, end, uot tests = ( (None, None, ""), (None, past, "Ended"), (None, y2000, "Ended 2000"), (None, y2100, "Will end 2100"), (None, future, "Ongoing"), (past, None, "Started"), (past, past, "Ended"), (past, y2000, "Ended 2000"), (past, y2100, "Will end 2100"), (past, future, "Ongoing"), (y2000, None, "Started 2000"), (y2000, past, "Started 2000, now ended"), (y2000, y2000, "2000 → 2000"), (y2000, y2100, "2000 → 2100"), (y2000, future, "Started 2000"), (y2100, None, "Will start 2100"), (y2100, y2100, "2100 → 2100"), (y2100, future, "Will start 2100"), (future, None, "Not started yet"), (future, future, "Not started yet"), # These are impossible, but we don't validate against them. Best check something # sensible is returned. Might need if we ever do a site for Time Lords! (y2100, past, "Will start 2100, now ended"), (y2100, y2000, "2100 → 2000"), (future, past, "Ended"), (future, y2000, "Ended 2000"), (future, y2100, "Will end 2100"), ) for start_date, end_date, expected in tests: position.start_date = start_date position.end_date = end_date actual = position.display_dates() self.assertEqual( actual, expected, "%s -> %s should be '%s', not '%s'" % (start_date, end_date, expected, actual))
def test_election_position_has_number(self): """ Positions on an election list must contain a number. """ pos = models.Position(person=self.person, organisation=self.election_list_da, title=self.title) pos._set_sorting_dates() with self.assertRaises(exceptions.ValidationError): pos.full_clean() pos.title = self.first_candidate pos.full_clean()
def test_have_at_least_one_attribute(self): """ Positions must have a person, and at least one more attribute. Otherwise they don't mean anything """ pos = models.Position(person=self.person, ) # call this manually so that the validation does not get all confused # about it pos._set_sorting_dates() with self.assertRaises(exceptions.ValidationError): pos.full_clean() # If this does not blow up then it is OK pos.organisation = self.organisation pos.full_clean()
def test_unicode(self): """Check that missing attributes don't crash""" position = models.Position(person=self.person, ) self.assertEqual(str(position), 'Test Person (??? at ???)')
def test_sorting(self): """Check that the sorting is as expected""" position_dates = [ # start_date, end_date, ( 'future', 'future', ), ( 'future', None, ), ( '2002', 'future', ), ( '2001', 'future', ), ('past', 'future'), ( None, 'future', ), ( 'future', '2010', ), ( '2010', None, ), ( '2002', '2010', ), ( '2001', '2010', ), ('past', '2010'), ( None, '2010', ), ( 'future', '2009', ), ( '2009', None, ), ( '2002', '2009', ), ( '2001', '2009', ), ('past', '2009'), ( None, '2009', ), ( '2002', None, ), ( '2001', None, ), ('future', 'past'), # <-- this is nonsensical ('2010', 'past'), ('2009', 'past'), ('past', 'past'), (None, 'past'), ('past', None), ( None, None, ), ] # create the positions, store the config in the notes and create a list to compare against position_expected_order = [] positions_to_save = [] def approx_date_from_entry(entry): if entry is None: return None if entry == 'future': return ApproximateDate(future=True) if entry == 'past': return ApproximateDate(past=True) return ApproximateDate(year=int(entry)) for dates in position_dates: note = u"%s -> %s" % dates start_date = approx_date_from_entry(dates[0]) end_date = approx_date_from_entry(dates[1]) position_expected_order.append(note) positions_to_save.append( models.Position( start_date=start_date, end_date=end_date, note=note, person=self.person, )) # save all the positions, but shuffle them first random.shuffle(positions_to_save) for position in positions_to_save: position.save() # get all the positions from db and check that they are sorted correctly positions_from_db = self.person.position_set.all() position_actual_order = [p.note for p in positions_from_db] # print # print position_actual_order # print # print position_expected_order # print self.maxDiff = None self.assertEqual(position_expected_order, position_actual_order)
def create_position(**kwargs): pos = models.Position(**kwargs) pos._set_sorting_dates() pos.full_clean( ) # needed as otherwise no validation occurs. Genius!
def handle(self, **options): coalition_member_title, created = models.PositionTitle.objects.get_or_create( name="Coalition Member", slug="coalition-member") # get a list of all parties in a coalition coalition_party_slugs = [ slug for slug in self.party_to_coalition_mapping.keys() if self.party_to_coalition_mapping[slug] ] # get all the parties representing those slugs coalition_parties = [ models.Organisation.objects.get(slug=slug) for slug in coalition_party_slugs ] # get all the positions of people who are currently members of those parties coalition_member_positions = (models.Position.objects.all().filter( title__slug='member').filter( organisation__in=coalition_parties).currently_active()) # get all current aspirant positions current_aspirant_positions = ( models.Position.objects.all().current_aspirant_positions()) # extract the people who are both members of a coalition party and currently an aspirant coalition_members = (models.Person.objects.all().filter( position__in=coalition_member_positions).filter( position__in=current_aspirant_positions).distinct()) coalition_memberships_to_end = set( models.Position.objects.all().filter( title=coalition_member_title).filter( organisation__kind__slug='coalition').filter( person__in=coalition_members).currently_active()) # for all the coalition members go through and ensure that they are linked to the coalition as well for member in coalition_members: for party in member.parties(): coalition_slug = self.party_to_coalition_mapping.get( party.slug) if coalition_slug: coalition = models.Organisation.objects.get( slug=coalition_slug) position_parameters = { 'title': coalition_member_title, 'person': member, 'organisation': coalition, 'category': 'political' } positions = models.Position.objects.all().currently_active( ).filter(**position_parameters) if len(positions) > 1: raise Exception, "Multiple positions matched %s" % ( position_parameters, ) elif len(positions) == 1: # There's still a current position that represents this: existing_position = positions[0] # Make sure that its end date is 'future': existing_position.end_date = 'future' existing_position.save() coalition_memberships_to_end.discard(existing_position) else: # Otherwise the position has to be created: new_position = models.Position(start_date=str( datetime.date.today()), end_date='future', **position_parameters) new_position.save() # End any coalition memberships that are no longer correct: for position in coalition_memberships_to_end: position.end_date = str(datetime.date.today() - datetime.timedelta(days=1)) position.save()