def sponsor_for(sponsor_dict): if sponsor_dict is None: # TODO: This can hopefully be removed. In testing s414-113 # was missing sponsor data. But all bills have a sponsor? return None # TODO: Don't do regex matching here. Find another way. m = re.match(r'(?P<title>(Rep|Sen))\. (?P<name>.*?) +\[(?P<party>[DRI])-(?P<state>[A-Z][A-Z])(-(?P<district>\d{1,2}|At Large))?\]$', sponsor_dict['fullName']) if m.group("district") is None: district = None # a senator elif m.group("district") == "At Large": district = None # TODO: For backwards compatibility, we're returning None, but 0 would be better. else: # TODO: For backwards compatibility, we're returning a string, but an int would be better. district = m.group('district') return { 'title': m.group("title"), 'name': m.group("name"), # the firstName, middleName, lastName fields have inconsistent capitalization - some are all uppercase 'district': district, 'state': m.group('state'), #'party': m.group('party'), 'thomas_id': utils.translate_legislator_id('bioguide', sponsor_dict['bioguideId'], 'thomas'), # TODO: Remove one day. 'bioguide_id': sponsor_dict['bioguideId'], 'type': 'person' }
def create_govtrack_xml(amdt, options): govtrack_type_codes = {'hr': 'h', 's': 's', 'hres': 'hr', 'sres': 'sr', 'hjres': 'hj', 'sjres': 'sj', 'hconres': 'hc', 'sconres': 'sc'} root = etree.Element("amendment") root.set("session", amdt['congress']) root.set("chamber", amdt['amendment_type'][0]) root.set("number", str(amdt['number'])) root.set("updated", utils.format_datetime(amdt['updated_at'])) make_node = utils.make_node if amdt.get("amends_bill", None): make_node(root, "amends", None, type=govtrack_type_codes[amdt["amends_bill"]["bill_type"]], number=str(amdt["amends_bill"]["number"]), sequence=str(amdt["house_number"]) if amdt.get("house_number", None) else "") elif amdt.get("amends_treaty", None): make_node(root, "amends", None, type="treaty", number=str(amdt["amends_treaty"]["number"])) make_node(root, "status", amdt['status'], datetime=amdt['status_at']) if amdt['sponsor'] and amdt['sponsor']['type'] == 'person': v = amdt['sponsor']['bioguide_id'] if not options.get("govtrack", False): make_node(root, "sponsor", None, bioguide_id=v) else: v = str(utils.translate_legislator_id('bioguide', v, 'govtrack')) make_node(root, "sponsor", None, id=v) elif amdt['sponsor'] and amdt['sponsor']['type'] == 'committee': make_node(root, "sponsor", None, committee=amdt['sponsor']['name']) else: make_node(root, "sponsor", None) make_node(root, "offered", None, datetime=amdt['introduced_at']) make_node(root, "description", amdt["description"] if amdt["description"] else amdt["purpose"]) if amdt["description"]: make_node(root, "purpose", amdt["purpose"]) actions = make_node(root, "actions", None) for action in amdt['actions']: a = make_node(actions, action['type'] if action['type'] in ("vote",) else "action", None, datetime=action['acted_at']) if action['type'] == 'vote': a.set("how", action["how"]) a.set("result", action["result"]) if action.get("roll") != None: a.set("roll", str(action["roll"])) if action.get('text'): make_node(a, "text", action['text']) if action.get('in_committee'): make_node(a, "committee", None, name=action['in_committee']) for cr in action['references']: make_node(a, "reference", None, ref=cr['reference'], label=cr['type']) return etree.tostring(root, pretty_print=True)
def create_govtrack_xml(amdt, options): govtrack_type_codes = {'hr': 'h', 's': 's', 'hres': 'hr', 'sres': 'sr', 'hjres': 'hj', 'sjres': 'sj', 'hconres': 'hc', 'sconres': 'sc'} root = etree.Element("amendment") root.set("session", amdt['congress']) root.set("chamber", amdt['amendment_type'][0]) root.set("number", str(amdt['number'])) root.set("updated", utils.format_datetime(amdt['updated_at'])) make_node = utils.make_node if amdt.get("amends_bill", None): make_node(root, "amends", None, type=govtrack_type_codes[amdt["amends_bill"]["bill_type"]], number=str(amdt["amends_bill"]["number"]), sequence=str(amdt["house_number"]) if amdt.get("house_number", None) else "") elif amdt.get("amends_treaty", None): make_node(root, "amends", None, type="treaty", number=str(amdt["amends_treaty"]["number"])) make_node(root, "status", amdt['status'], datetime=amdt['status_at']) if amdt['sponsor'] and amdt['sponsor']['type'] == 'person': v = amdt['sponsor']['thomas_id'] if not options.get("govtrack", False): make_node(root, "sponsor", None, thomas_id=v) else: v = str(utils.translate_legislator_id('thomas', v, 'govtrack')) make_node(root, "sponsor", None, id=v) elif amdt['sponsor'] and amdt['sponsor']['type'] == 'committee': make_node(root, "sponsor", None, committee=amdt['sponsor']['name']) else: make_node(root, "sponsor", None) make_node(root, "offered", None, datetime=amdt['introduced_at']) make_node(root, "description", amdt["description"] if amdt["description"] else amdt["purpose"]) if amdt["description"]: make_node(root, "purpose", amdt["purpose"]) actions = make_node(root, "actions", None) for action in amdt['actions']: a = make_node(actions, action['type'] if action['type'] in ("vote",) else "action", None, datetime=action['acted_at']) if action['type'] == 'vote': a.set("how", action["how"]) a.set("result", action["result"]) if action.get("roll") != None: a.set("roll", str(action["roll"])) if action.get('text'): make_node(a, "text", action['text']) if action.get('in_committee'): make_node(a, "committee", None, name=action['in_committee']) for cr in action['references']: make_node(a, "reference", None, ref=cr['reference'], label=cr['type']) return etree.tostring(root, pretty_print=True)
def make_node(parent, tag, text, **attrs): if options.get("govtrack", False): # Rewrite bioguide_id attributes as just id with GovTrack person IDs. attrs2 = {} for k, v in attrs.items(): if v: if k == "bioguide_id": # remap "bioguide_id" attributes to govtrack "id" k = "id" v = str(utils.translate_legislator_id('bioguide', v, 'govtrack')) if k == "thomas_id": # remap "thomas_id" attributes to govtrack "id" k = "id" v = str(utils.translate_legislator_id('thomas', v, 'govtrack')) attrs2[k] = v attrs = attrs2 return utils.make_node(parent, tag, text, **attrs)
def make_node(parent, tag, text, **attrs): if options.get("govtrack", False): # Rewrite bioguide_id attributes as just id with GovTrack person IDs. attrs2 = {} for k, v in attrs.items(): if v: if k == "bioguide_id": # remap "bioguide_id" attributes to govtrack "id" k = "id" v = str(utils.translate_legislator_id('bioguide', v, 'govtrack')) attrs2[k] = v attrs = attrs2 return utils.make_node(parent, tag, text, **attrs)
def output_vote(vote, options, id_type=None): logging.info("[%s] Writing to disk..." % vote['vote_id']) # output JSON - so easy! utils.write( json.dumps(vote, sort_keys=True, indent=2, default=utils.format_datetime), output_for_vote(vote["vote_id"], "json"), options=options ) # What kind of IDs are we passed for Members of Congress? # For current data, we infer from the chamber. For historical data from voteview, # we're passed the type in id_type, which is set to "bioguide". if not id_type: id_type = ("bioguide" if vote["chamber"] == "h" else "lis") # output XML root = etree.Element("roll") root.set("where", "house" if vote['chamber'] == "h" else "senate") root.set("session", str(vote["congress"])) root.set("year", str(vote["date"].year)) root.set("roll", str(vote["number"])) if "voteview" in vote["source_url"]: root.set("source", "keithpoole") else: root.set("source", "house.gov" if vote["chamber"] == "h" else "senate.gov") root.set("datetime", utils.format_datetime(vote['date'])) root.set("updated", utils.format_datetime(vote['updated_at'])) def get_votes(option): return len(vote["votes"].get(option, [])) root.set("aye", str(get_votes("Yea") + get_votes("Aye"))) root.set("nay", str(get_votes("Nay") + get_votes("No"))) root.set("nv", str(get_votes("Not Voting"))) root.set("present", str(get_votes("Present"))) utils.make_node(root, "category", vote["category"]) utils.make_node(root, "type", vote["type"]) utils.make_node(root, "question", vote["question"]) utils.make_node(root, "required", vote["requires"]) utils.make_node(root, "result", vote["result"]) if vote.get("bill"): govtrack_type_codes = {'hr': 'h', 's': 's', 'hres': 'hr', 'sres': 'sr', 'hjres': 'hj', 'sjres': 'sj', 'hconres': 'hc', 'sconres': 'sc'} utils.make_node(root, "bill", None, session=str(vote["bill"]["congress"]), type=govtrack_type_codes[vote["bill"]["type"]], number=str(vote["bill"]["number"])) if "amendment" in vote: n = utils.make_node(root, "amendment", None) if vote["amendment"]["type"] == "s": n.set("ref", "regular") n.set("session", str(vote["congress"])) n.set("number", "s" + str(vote["amendment"]["number"])) elif vote["amendment"]["type"] == "h-bill": n.set("ref", "bill-serial") n.set("session", str(vote["congress"])) n.set("number", str(vote["amendment"]["number"])) # well-known keys for certain vote types: +/-/P/0 option_keys = {"Aye": "+", "Yea": "+", "Nay": "-", "No": "-", "Present": "P", "Not Voting": "0", "Guilty": "+", "Not Guilty": "-" } # preferred order of output: ayes, nays, present, then not voting, and similarly for guilty/not-guilty # and handling other options like people's names for votes for the Speaker. option_sort_order = ('Aye', 'Yea', 'Guilty', 'No', 'Nay', 'Not Guilty', 'OTHER', 'Present', 'Not Voting') options_list = sorted(vote["votes"].keys(), key=lambda o: option_sort_order.index(o) if o in option_sort_order else option_sort_order.index("OTHER")) for option in options_list: if option not in option_keys: option_keys[option] = option utils.make_node(root, "option", option, key=option_keys[option]) for option in options_list: for v in vote["votes"][option]: n = utils.make_node(root, "voter", None) if v == "VP": n.set("id", "0") n.set("VP", "1") elif not options.get("govtrack", False): n.set("id", str(v["id"])) else: n.set("id", str(utils.translate_legislator_id(id_type, v["id"], 'govtrack'))) n.set("vote", option_keys[option]) n.set("value", option) if v != "VP": n.set("state", v["state"]) if v.get("voteview_votecode_extra") is not None: n.set("voteview_votecode_extra", v["voteview_votecode_extra"]) xmloutput = etree.tostring(root, pretty_print=True, encoding="utf8") # mimick two hard line breaks in GovTrack's legacy output to ease running diffs xmloutput = re.sub('(source=".*?") ', r"\1\n ", xmloutput) xmloutput = re.sub('(updated=".*?") ', r"\1\n ", xmloutput) utils.write( xmloutput, output_for_vote(vote['vote_id'], "xml"), options=options )
def output_vote(vote, options, id_type=None): logging.info("[%s] Writing to disk..." % vote['vote_id']) # output JSON - so easy! utils.write(json.dumps(vote, sort_keys=True, indent=2, default=utils.format_datetime), output_for_vote(vote["vote_id"], "json"), options=options) # What kind of IDs are we passed for Members of Congress? # For current data, we infer from the chamber. For historical data from voteview, # we're passed the type in id_type, which is set to "bioguide". if not id_type: id_type = ("bioguide" if vote["chamber"] == "h" else "lis") # output XML root = etree.Element("roll") root.set("where", "house" if vote['chamber'] == "h" else "senate") root.set("session", str(vote["congress"])) root.set("year", str(vote["date"].year)) root.set("roll", str(vote["number"])) if "voteview" in vote["source_url"]: root.set("source", "keithpoole") else: root.set("source", "house.gov" if vote["chamber"] == "h" else "senate.gov") root.set("datetime", utils.format_datetime(vote['date'])) root.set("updated", utils.format_datetime(vote['updated_at'])) def get_votes(option): return len(vote["votes"].get(option, [])) root.set("aye", str(get_votes("Yea") + get_votes("Aye"))) root.set("nay", str(get_votes("Nay") + get_votes("No"))) root.set("nv", str(get_votes("Not Voting"))) root.set("present", str(get_votes("Present"))) utils.make_node(root, "category", vote["category"]) utils.make_node(root, "type", vote["type"]) utils.make_node(root, "question", vote["question"]) utils.make_node(root, "required", vote["requires"]) utils.make_node(root, "result", vote["result"]) if vote.get("bill"): govtrack_type_codes = { 'hr': 'h', 's': 's', 'hres': 'hr', 'sres': 'sr', 'hjres': 'hj', 'sjres': 'sj', 'hconres': 'hc', 'sconres': 'sc' } utils.make_node(root, "bill", None, session=str(vote["bill"]["congress"]), type=govtrack_type_codes[vote["bill"]["type"]], number=str(vote["bill"]["number"])) if "amendment" in vote: n = utils.make_node(root, "amendment", None) if vote["amendment"]["type"] == "s": n.set("ref", "regular") n.set("session", str(vote["congress"])) n.set("number", "s" + str(vote["amendment"]["number"])) elif vote["amendment"]["type"] == "h-bill": n.set("ref", "bill-serial") n.set("session", str(vote["congress"])) n.set("number", str(vote["amendment"]["number"])) # well-known keys for certain vote types: +/-/P/0 option_keys = { "Aye": "+", "Yea": "+", "Nay": "-", "No": "-", "Present": "P", "Not Voting": "0", "Guilty": "+", "Not Guilty": "-" } # preferred order of output: ayes, nays, present, then not voting, and similarly for guilty/not-guilty # and handling other options like people's names for votes for the Speaker. option_sort_order = ('Aye', 'Yea', 'Guilty', 'No', 'Nay', 'Not Guilty', 'OTHER', 'Present', 'Not Voting') options_list = sorted( vote["votes"].keys(), key=lambda o: option_sort_order.index(o) if o in option_sort_order else option_sort_order.index("OTHER")) for option in options_list: if option not in option_keys: option_keys[option] = option utils.make_node(root, "option", option, key=option_keys[option]) for option in options_list: for v in vote["votes"][option]: # Rep-elect Letlow is included as not voting in the first House vote of the 117th Congress # where the clerk calls a quorum roll call. But because Letlow had died prior to this date, # he is not represented in congress-legislators and has no GovTrack-id, and so we cannot # represent this record in the data. if isinstance(v, dict) and v["id"] == "L000555" and options.get( "govtrack", False): continue n = utils.make_node(root, "voter", None) if v == "VP": n.set("id", "0") n.set("VP", "1") elif not options.get("govtrack", False): n.set("id", str(v["id"])) else: n.set( "id", str( utils.translate_legislator_id(id_type, v["id"], 'govtrack'))) n.set("vote", option_keys[option]) n.set("value", option) if v != "VP": n.set("state", v["state"]) if v.get("voteview_votecode_extra") is not None: n.set("voteview_votecode_extra", v["voteview_votecode_extra"]) xmloutput = etree.tostring(root, pretty_print=True, encoding="unicode") # mimick two hard line breaks in GovTrack's legacy output to ease running diffs xmloutput = re.sub('(source=".*?") ', r"\1\n ", xmloutput) xmloutput = re.sub('(updated=".*?") ', r"\1\n ", xmloutput) utils.write(xmloutput, output_for_vote(vote['vote_id'], "xml"), options=options)