def test_full_vote_event(): j = create_jurisdiction() j.legislative_sessions.create(name="1900", identifier="1900") sp1 = ScrapePerson("John Smith", primary_org="lower") sp2 = ScrapePerson("Adam Smith", primary_org="lower") org = ScrapeOrganization(name="House", classification="lower") bill = ScrapeBill("HB 1", "1900", "Axe & Tack Tax Act", from_organization=org._id) vote_event = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", organization=org._id, ) vote_event.set_count("yes", 20) vote_event.yes("John Smith") vote_event.no("Adam Smith") oi = OrganizationImporter("jid") oi.import_data([org.as_dict()]) pi = PersonImporter("jid") pi.import_data([sp1.as_dict(), sp2.as_dict()]) mi = MembershipImporter("jid", pi, oi, DumbMockImporter()) mi.import_data([sp1._related[0].as_dict(), sp2._related[0].as_dict()]) bi = BillImporter("jid", oi, pi) bi.import_data([bill.as_dict()]) VoteEventImporter("jid", pi, oi, bi).import_data([vote_event.as_dict()]) assert VoteEvent.objects.count() == 1 ve = VoteEvent.objects.get() assert ve.legislative_session == LegislativeSession.objects.get() assert ve.motion_classification == ["passage:bill"] assert ve.bill == Bill.objects.get() count = ve.counts.get() assert count.option == "yes" assert count.value == 20 votes = list(ve.votes.all()) assert len(votes) == 2 for v in ve.votes.all(): if v.voter_name == "John Smith": assert v.option == "yes" assert v.voter == Person.objects.get(name="John Smith") else: assert v.option == "no" assert v.voter == Person.objects.get(name="Adam Smith")
def test_vote_event_bill_actions_two_stage(): # this test is very similar to what we're testing in test_vote_event_bill_actions w/ # ve3 and ve4, that two bills that reference the same action won't conflict w/ the # OneToOneField, but in this case we do it in two stages so that the conflict is found # even if the votes weren't in the same scrape create_jurisdiction() bill = ScrapeBill("HB 1", "1900", "Axe & Tack Tax Act", chamber="lower") bill.add_action(description="passage", date="1900-04-02", chamber="lower") ve1 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", chamber="lower", ) ve2 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", chamber="lower", ) # disambiguate them ve1.pupa_id = "one" ve2.pupa_id = "two" bi = BillImporter("jid") bi.import_data([bill.as_dict()]) # first imports just fine VoteEventImporter("jid", bi).import_data([ve1.as_dict()]) votes = list(VoteEvent.objects.all()) assert len(votes) == 1 assert votes[0].bill_action is not None # when second is imported, ensure that action stays pinned to first just as it would # have if they were both in same import VoteEventImporter("jid", bi).import_data([ve1.as_dict(), ve2.as_dict()]) votes = list(VoteEvent.objects.all()) assert len(votes) == 2 assert votes[0].bill_action is not None assert votes[1].bill_action is None
def test_fix_bill_id(): j = create_jurisdiction() j.legislative_sessions.create(name="1900", identifier="1900") org1 = ScrapeOrganization(name="House", classification="lower") bill = ScrapeBill("HB 1", "1900", "Test Bill ID", classification="bill", chamber="lower") oi = OrganizationImporter("jid") oi.import_data([org1.as_dict()]) from openstates.settings import IMPORT_TRANSFORMERS IMPORT_TRANSFORMERS["bill"] = { "identifier": lambda x: re.sub(r"([A-Z]*)\s*0*([-\d]+)", r"\1 \2", x, 1) } bi = BillImporter("jid", oi, DumbMockImporter()) bi.import_data([bill.as_dict()]) ve = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="fail", bill_chamber="lower", bill="HB1", identifier="4", bill_action="passage", organization=org1._id, ) VoteEventImporter("jid", DumbMockImporter(), oi, bi).import_data([ve.as_dict()]) IMPORT_TRANSFORMERS["bill"] = {} ve = VoteEvent.objects.get() ve.bill.identifier == "HB 1"
def test_full_vote_event(): create_jurisdiction() bill = ScrapeBill("HB 1", "1900", "Axe & Tack Tax Act", chamber="lower") vote_event = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", chamber="lower", ) vote_event.set_count("yes", 20) vote_event.yes("John Smith") vote_event.no("Adam Smith") Person.objects.create(name="John Smith") Person.objects.create(name="Adam Smith") for person in Person.objects.all(): person.memberships.create(organization=Organization.objects.get( classification="lower")) bi = BillImporter("jid") bi.import_data([bill.as_dict()]) VoteEventImporter("jid", bi).import_data([vote_event.as_dict()]) assert VoteEvent.objects.count() == 1 ve = VoteEvent.objects.get() assert ve.legislative_session == LegislativeSession.objects.get() assert ve.motion_classification == ["passage:bill"] assert ve.bill == Bill.objects.get() count = ve.counts.get() assert count.option == "yes" assert count.value == 20 votes = list(ve.votes.all()) assert len(votes) == 2 for v in ve.votes.all(): if v.voter_name == "John Smith": assert v.option == "yes" assert v.voter == Person.objects.get(name="John Smith") else: assert v.option == "no" assert v.voter == Person.objects.get(name="Adam Smith")
def test_locked_field_subitem(): create_jurisdiction() bill = ScrapeBill("HB 1", "2020", "Title") bill.add_source("https://example.com") bi = BillImporter("jid") bi.import_data([bill.as_dict()]) # lock the field b = Bill.objects.get() b.locked_fields = ["sources"] b.save() # reimport (without source) bill = ScrapeBill("HB 1", "2020", "Title") bi = BillImporter("jid") bi.import_data([bill.as_dict()]) b = Bill.objects.get() assert b.sources.count() == 1 assert b.locked_fields == ["sources"]
def test_resolve_json_id(): create_jurisdiction() p1 = ScrapeBill("HB 1", "2020", "Title").as_dict() p2 = ScrapeBill("HB 1", "2020", "Title").as_dict() bi = BillImporter("jid") # do import and get database id p1_id = p1["_id"] p2_id = p2["_id"] bi.import_data([p1, p2]) db_id = Bill.objects.get().id # simplest case assert bi.resolve_json_id(p1_id) == db_id # duplicate should resolve to same id assert bi.resolve_json_id(p2_id) == db_id # a null id should map to None assert bi.resolve_json_id(None) is None # no such id with pytest.raises(UnresolvedIdError): bi.resolve_json_id("this-is-invalid")
def test_fix_bill_id(): create_jurisdiction() create_org() bill = ScrapeBill("hb1", "1900", "Test Bill ID", classification="bill", chamber="lower") from openstates.settings import IMPORT_TRANSFORMERS IMPORT_TRANSFORMERS["bill"] = { "identifier": fix_bill_id, } bi = BillImporter("jid") bi.import_data([bill.as_dict()]) IMPORT_TRANSFORMERS["bill"] = {} b = Bill.objects.get() assert b.identifier == "HB 1"
def test_locked_field(): create_jurisdiction() bill = ScrapeBill("HB 1", "2020", "Title").as_dict() bi = BillImporter("jid") bi.import_data([bill]) # set classification and lock field b = Bill.objects.get() b.classification = ["locked"] b.locked_fields = ["classification"] b.save() # reimport bill = ScrapeBill("HB 1", "2020", "Title").as_dict() bi = BillImporter("jid") bi.import_data([bill]) b = Bill.objects.get() assert b.classification == ["locked"] assert b.locked_fields == ["classification"] # do it a third time to check for the locked_fields reversion issue bill = ScrapeBill("HB 1", "2020", "Title").as_dict() bi = BillImporter("jid") bi.import_data([bill]) b = Bill.objects.get() assert b.classification == ["locked"] assert b.locked_fields == ["classification"]
def test_fix_bill_id(): create_jurisdiction() create_org() bill = ScrapeBill("HB1", "1900", "Test Bill ID", classification="bill", chamber="lower") from openstates.settings import IMPORT_TRANSFORMERS IMPORT_TRANSFORMERS["bill"] = { "identifier": lambda x: re.sub(r"([A-Z]*)\s*0*([-\d]+)", r"\1 \2", x, 1) } bi = BillImporter("jid") bi.import_data([bill.as_dict()]) IMPORT_TRANSFORMERS["bill"] = {} b = Bill.objects.get() assert b.identifier == "HB 1"
def test_fix_bill_id(): create_jurisdiction() bill = ScrapeBill("HB 1", "1900", "Test Bill ID", classification="bill", chamber="lower") from openstates.settings import IMPORT_TRANSFORMERS IMPORT_TRANSFORMERS["bill"] = { "identifier": fix_bill_id, } bi = BillImporter("jid") bi.import_data([bill.as_dict()]) ve = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="fail", bill_chamber="lower", bill="HB1", identifier="4", bill_action="passage", chamber="lower", ) VoteEventImporter("jid", bi).import_data([ve.as_dict()]) IMPORT_TRANSFORMERS["bill"] = {} ve = VoteEvent.objects.get() ve.bill.identifier == "HB 1"
def test_vote_event_bill_actions_errors(): j = create_jurisdiction() j.legislative_sessions.create(name="1900", identifier="1900") org1 = ScrapeOrganization(name="House", classification="lower") org2 = ScrapeOrganization(name="Senate", classification="upper") bill = ScrapeBill("HB 1", "1900", "Axe & Tack Tax Act", from_organization=org1._id) # for this bill, two identical actions, so vote matching will fail bill.add_action(description="passage", date="1900-04-01", chamber="lower") bill.add_action(description="passage", date="1900-04-01", chamber="lower") # this action is good, but two votes will try to match it bill.add_action(description="passage", date="1900-04-02", chamber="lower") # will match two actions ve1 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", identifier="1", bill_action="passage", organization=org1._id, ) # will match no actions ve2 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", identifier="2", bill_action="committee result", organization=org1._id, ) # these two votes will both match the same action ve3 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", identifier="3", bill_action="passage", organization=org1._id, ) ve4 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage-syz", start_date="1900-04-02", classification="passage:bill", result="fail", bill_chamber="lower", bill="HB 1", identifier="4", bill_action="passage", organization=org1._id, ) oi = OrganizationImporter("jid") oi.import_data([org1.as_dict(), org2.as_dict()]) bi = BillImporter("jid", oi, DumbMockImporter()) bi.import_data([bill.as_dict()]) VoteEventImporter("jid", DumbMockImporter(), oi, bi).import_data( [ve1.as_dict(), ve2.as_dict(), ve3.as_dict(), ve4.as_dict()]) bill = Bill.objects.get() votes = list(VoteEvent.objects.all().order_by("identifier")) # isn't matched, was ambiguous across two actions assert votes[0].bill_action is None # isn't matched, no match in actions assert votes[1].bill_action is None # these both try to match the same action, only first will succeed assert votes[2].bill_action is not None assert votes[3].bill_action is None
def test_vote_event_bill_actions(): j = create_jurisdiction() j.legislative_sessions.create(name="1900", identifier="1900") org1 = ScrapeOrganization(name="House", classification="lower") org2 = ScrapeOrganization(name="Senate", classification="upper") bill = ScrapeBill("HB 1", "1900", "Axe & Tack Tax Act", from_organization=org1._id) # add actions, passage of upper & lower on same day, something else, # then passage in upper again on a different day bill.add_action(description="passage", date="1900-04-01", chamber="upper") bill.add_action(description="passage", date="1900-04-01", chamber="lower") bill.add_action(description="other event", date="1900-04-01", chamber="lower") bill.add_action(description="passage", date="1900-04-02", chamber="upper") # four passage votes, one per chamber, one on 04-01, and one on 04-02 ve1 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", organization=org1._id, ) ve2 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-01", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", organization=org2._id, ) ve3 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", organization=org1._id, ) ve4 = ScrapeVoteEvent( legislative_session="1900", motion_text="passage", start_date="1900-04-02", classification="passage:bill", result="pass", bill_chamber="lower", bill="HB 1", bill_action="passage", organization=org2._id, ) oi = OrganizationImporter("jid") oi.import_data([org1.as_dict(), org2.as_dict()]) bi = BillImporter("jid", oi, DumbMockImporter()) bi.import_data([bill.as_dict()]) VoteEventImporter("jid", DumbMockImporter(), oi, bi).import_data( [ve1.as_dict(), ve2.as_dict(), ve3.as_dict(), ve4.as_dict()]) bill = Bill.objects.get() votes = list(VoteEvent.objects.all()) actions = list(bill.actions.all()) assert len(actions) == 4 assert len(votes) == 4 votes = {(v.organization.classification, v.start_date): v.bill_action for v in votes} # ensure that votes are matched using action, chamber, and date assert votes[("upper", "1900-04-01")] == actions[0] assert votes[("lower", "1900-04-01")] == actions[1] assert votes[("upper", "1900-04-02")] == actions[3] assert votes[("lower", "1900-04-02")] is None