예제 #1
0
파일: vote_info.py 프로젝트: JT5D/congress
 def add_vote(vote_option, voter):
   if vote_option == "Present, Giving Live Pair": vote_option = "Present"
   vote["votes"].setdefault(vote_option, []).append(voter)
   
   # In the 101st Congress, 1st session (1989), votes 133 through 136 lack lis_member_id nodes.
   if voter != "VP" and voter["id"] == "":
     logging.warn("Missing lis_member_id in %s, falling back to name lookup for %s" % (vote["vote_id"], voter["last_name"]))
     voter["id"] = utils.lookup_legislator(vote["congress"], "sen", voter["last_name"], voter["state"], voter["party"], vote["date"], "lis")
     if voter["id"] == None:
       raise Exception("Could not find ID for %s (%s-%s)" % (voter["last_name"], voter["state"], voter["party"]))
예제 #2
0
 def add_vote(vote_option, voter):
   if vote_option == "Present, Giving Live Pair": vote_option = "Present"
   vote["votes"].setdefault(vote_option, []).append(voter)
   
   # In the 101st Congress, 1st session (1989), votes 133 through 136 lack lis_member_id nodes.
   if voter != "VP" and voter["id"] == "":
     voter["id"] = utils.lookup_legislator(vote["congress"], "sen", voter["last_name"], voter["state"], voter["party"], vote["date"], "lis")
     if voter["id"] == None:
       logging.error("[%s] Missing lis_member_id and name lookup failed for %s" % (vote["vote_id"], voter["last_name"]))
       raise Exception("Could not find ID for %s (%s-%s)" % (voter["last_name"], voter["state"], voter["party"]))
     else:
       logging.info("[%s] Missing lis_member_id, falling back to name lookup for %s" % (vote["vote_id"], voter["last_name"]))
예제 #3
0
파일: vote_info.py 프로젝트: JT5D/congress
def parse_house_vote(dom, vote):
  def parse_date(d):
    d = d.strip()
    if " " in d:
      return datetime.datetime.strptime(d, "%d-%b-%Y %I:%M %p")
    else: # some votes have no times?
      print vote
      return datetime.datetime.strptime(d, "%d-%b-%Y")

  vote["date"] = parse_date(str(dom.xpath("string(vote-metadata/action-date)")) + " " + str(dom.xpath("string(vote-metadata/action-time)")))
  vote["question"] = unicode(dom.xpath("string(vote-metadata/vote-question)"))
  vote["type"] = unicode(dom.xpath("string(vote-metadata/vote-question)"))
  vote["type"] = normalize_vote_type(vote["type"])
  vote["category"] = get_vote_category(vote["question"])
  vote["subject"] = unicode(dom.xpath("string(vote-metadata/vote-desc)"))
  if not vote["subject"]: del vote["subject"]
  
  vote_types = { "YEA-AND-NAY": "1/2", "2/3 YEA-AND-NAY": "2/3", "3/5 YEA-AND-NAY": "3/5", "1/2": "1/2", "2/3" : "2/3", "QUORUM": "QUORUM", "RECORDED VOTE" : "1/2", "2/3 RECORDED VOTE": "2/3", "3/5 RECORDED VOTE": "3/5" }
  vote["requires"] = vote_types.get(str(dom.xpath("string(vote-metadata/vote-type)")), "unknown")
  
  vote["result_text"] = unicode(dom.xpath("string(vote-metadata/vote-result)"))
  vote["result"] = unicode(dom.xpath("string(vote-metadata/vote-result)"))
  
  bill_num = unicode(dom.xpath("string(vote-metadata/legis-num)"))
  if bill_num not in ("", "QUORUM", "JOURNAL", "MOTION", "ADJOURN") and not re.match(r"QUORUM \d+$", bill_num):
    bill_types = { "S": "s", "S CON RES": "sconres", "S J RES": "sjres", "S RES": "sres", "H R": "hr", "H CON RES": "hconres", "H J RES": "hjres", "H RES": "hres" }
    try:
      bill_type, bill_number = bill_num.rsplit(" ", 1)
      vote["bill"] = {
        "congress": vote["congress"],
        "type": bill_types[bill_type],
        "number": int(bill_number)
      }
    except ValueError: # rsplit failed, i.e. there is no space in the legis-num field
      raise Exception("Unhandled bill number in the legis-num field")
    
  if str(dom.xpath("string(vote-metadata/amendment-num)")):
    vote["amendment"] = {
      "type": "h-bill",
      "number": int(str(dom.xpath("string(vote-metadata/amendment-num)"))),
      "author": unicode(dom.xpath("string(vote-metadata/amendment-author)")),
    }

  # Assemble a complete question from the vote type, amendment, and bill number.
  if "amendment" in vote and "bill" in vote:
    vote["question"] += ": Amendment %s to %s" % (vote["amendment"]["number"], unicode(dom.xpath("string(vote-metadata/legis-num)")))
  elif "amendment" in vote:
    vote["question"] += ": Amendment %s to [unknown bill]" % vote["amendment"]["number"]
  elif "bill" in vote:
    vote["question"] += ": " + unicode(dom.xpath("string(vote-metadata/legis-num)"))
    if "subject" in vote: vote["question"] += " " + vote["subject"]
  elif "subject" in vote:
    vote["question"] += ": " + vote["subject"]

  # Count up the votes.
  vote["votes"] = { } # by vote type
  def add_vote(vote_option, voter):
    vote["votes"].setdefault(vote_option, []).append(voter)
  
  # Ensure the options are noted, even if no one votes that way.
  if unicode(dom.xpath("string(vote-metadata/vote-question)")) == "Election of the Speaker":
    for n in dom.xpath('vote-metadata/vote-totals/totals-by-candidate/candidate'):
      vote["votes"][n.text] = []
  elif unicode(dom.xpath("string(vote-metadata/vote-question)")) == "Call of the House":
    for n in dom.xpath('vote-metadata/vote-totals/totals-by-candidate/candidate'):
      vote["votes"][n.text] = []
  elif "YEA-AND-NAY" in dom.xpath('string(vote-metadata/vote-type)'):
    vote["votes"]['Yea'] = []
    vote["votes"]['Nay'] = []
    vote["votes"]['Present'] = []
    vote["votes"]['Not Voting'] = []
  else:
    vote["votes"]['Aye'] = []
    vote["votes"]['No'] = []
    vote["votes"]['Present'] = []
    vote["votes"]['Not Voting'] = []
  
  for member in dom.xpath("vote-data/recorded-vote"):
    display_name = unicode(member.xpath("string(legislator)"))
    state = str(member.xpath("string(legislator/@state)"))
    party = str(member.xpath("string(legislator/@party)"))
    vote_cast = str(member.xpath("string(vote)"))
    bioguideid = str(member.xpath("string(legislator/@name-id)"))
    add_vote(vote_cast, {
        "id": bioguideid,
        "state": state,
        "party": party,
        "display_name": display_name,
    })
    
  # Through the 107th Congress and sporadically in more recent data, the bioguide field
  # is not present. Look up the Members' bioguide IDs by name/state/party/date. This works
  # reasonably well, but there are many gaps. When there's a gap, it raises an exception
  # and the file is not saved.
  #
  # Take into account that the vote may list both a "Smith" and a "Smith, John". Resolve
  # "Smith" by process of elimination, i.e. he must not be whoever "Smith, John" resolved
  # to. To do that, process the voters from longest specified display name to shortest.
  #
  # One example of a sporadic case is 108th Congress, 2nd session (2004), votes 405 through
  # 544, where G.K. Butterfield's bioguide ID is 000000. It should have been B001251.
  # See https://github.com/unitedstates/congress/issues/46.
  
  seen_ids = set()
  all_voters = sum(vote["votes"].values(), [])
  all_voters.sort(key = lambda v : len(v["display_name"]), reverse=True) # process longer names first
  for v in all_voters:
    if v["id"] not in ("", "0000000"): continue

    if vote["congress"] > 107:
      logging.warn("Missing bioguide ID in %s, falling back to name lookup for %s" % (vote["vote_id"], v["display_name"]))

    # get the last name without the state abbreviation in parenthesis, if it is present
    display_name = v["display_name"]
    ss = " (%s)" % v["state"]
    if display_name.endswith(ss): display_name = display_name[:-len(ss)]

    # look up ID
    v["id"] = utils.lookup_legislator(vote["congress"], "rep", display_name, v["state"], v["party"], vote["date"], "bioguide", exclude=seen_ids)
      
    if v["id"] == None:
      raise Exception("No bioguide ID for %s (%s-%s)" % (display_name, v["state"], v["party"]))
    else:
      seen_ids.add(v["id"])
예제 #4
0
def parse_house_vote(dom, vote):
    def parse_date(d):
        d = d.strip()
        if " " in d:
            return datetime.datetime.strptime(d, "%d-%b-%Y %I:%M %p")
        else:  # some votes have no times?
            print vote
            return datetime.datetime.strptime(d, "%d-%b-%Y")

    vote["date"] = parse_date(
        str(dom.xpath("string(vote-metadata/action-date)")) + " " +
        str(dom.xpath("string(vote-metadata/action-time)")))
    vote["question"] = unicode(
        dom.xpath("string(vote-metadata/vote-question)"))
    vote["type"] = unicode(dom.xpath("string(vote-metadata/vote-question)"))
    vote["type"] = normalize_vote_type(vote["type"])
    if unicode(dom.xpath("string(vote-metadata/vote-desc)")).startswith(
            "Impeaching "):
        vote["category"] = "impeachment"
    else:
        vote["category"] = get_vote_category(vote["question"])
    vote["subject"] = unicode(dom.xpath("string(vote-metadata/vote-desc)"))
    if not vote["subject"]:
        del vote["subject"]

    vote_types = {
        "YEA-AND-NAY": "1/2",
        "2/3 YEA-AND-NAY": "2/3",
        "3/5 YEA-AND-NAY": "3/5",
        "1/2": "1/2",
        "2/3": "2/3",
        "QUORUM": "QUORUM",
        "RECORDED VOTE": "1/2",
        "2/3 RECORDED VOTE": "2/3",
        "3/5 RECORDED VOTE": "3/5"
    }
    vote["requires"] = vote_types.get(
        str(dom.xpath("string(vote-metadata/vote-type)")), "unknown")

    vote["result_text"] = unicode(
        dom.xpath("string(vote-metadata/vote-result)"))
    vote["result"] = unicode(dom.xpath("string(vote-metadata/vote-result)"))

    bill_num = unicode(dom.xpath("string(vote-metadata/legis-num)"))
    if bill_num not in ("", "QUORUM", "JOURNAL", "MOTION",
                        "ADJOURN") and not re.match(r"QUORUM \d+$", bill_num):
        bill_types = {
            "S": "s",
            "S CON RES": "sconres",
            "S J RES": "sjres",
            "S RES": "sres",
            "H R": "hr",
            "H CON RES": "hconres",
            "H J RES": "hjres",
            "H RES": "hres"
        }
        try:
            bill_type, bill_number = bill_num.rsplit(" ", 1)
            vote["bill"] = {
                "congress": vote["congress"],
                "type": bill_types[bill_type],
                "number": int(bill_number)
            }
        except ValueError:  # rsplit failed, i.e. there is no space in the legis-num field
            raise Exception("Unhandled bill number in the legis-num field")

    if str(dom.xpath("string(vote-metadata/amendment-num)")):
        vote["amendment"] = {
            "type": "h-bill",
            "number":
            int(str(dom.xpath("string(vote-metadata/amendment-num)"))),
            "author":
            unicode(dom.xpath("string(vote-metadata/amendment-author)")),
        }

    # Assemble a complete question from the vote type, amendment, and bill number.
    if "amendment" in vote and "bill" in vote:
        vote["question"] += ": Amendment %s to %s" % (
            vote["amendment"]["number"],
            unicode(dom.xpath("string(vote-metadata/legis-num)")))
    elif "amendment" in vote:
        vote["question"] += ": Amendment %s to [unknown bill]" % vote[
            "amendment"]["number"]
    elif "bill" in vote:
        vote["question"] += ": " + unicode(
            dom.xpath("string(vote-metadata/legis-num)"))
        if "subject" in vote:
            vote["question"] += " " + vote["subject"]
    elif "subject" in vote:
        vote["question"] += ": " + vote["subject"]

    # Count up the votes.
    vote["votes"] = {}  # by vote type

    def add_vote(vote_option, voter):
        vote["votes"].setdefault(vote_option, []).append(voter)

    # Ensure the options are noted, even if no one votes that way.
    if unicode(dom.xpath("string(vote-metadata/vote-question)")
               ) == "Election of the Speaker":
        for n in dom.xpath(
                'vote-metadata/vote-totals/totals-by-candidate/candidate'):
            vote["votes"][n.text] = []
    elif unicode(dom.xpath(
            "string(vote-metadata/vote-question)")) == "Call of the House":
        for n in dom.xpath(
                'vote-metadata/vote-totals/totals-by-candidate/candidate'):
            vote["votes"][n.text] = []
    elif "YEA-AND-NAY" in dom.xpath('string(vote-metadata/vote-type)'):
        vote["votes"]['Yea'] = []
        vote["votes"]['Nay'] = []
        vote["votes"]['Present'] = []
        vote["votes"]['Not Voting'] = []
    else:
        vote["votes"]['Aye'] = []
        vote["votes"]['No'] = []
        vote["votes"]['Present'] = []
        vote["votes"]['Not Voting'] = []

    for member in dom.xpath("vote-data/recorded-vote"):
        display_name = unicode(member.xpath("string(legislator)"))
        state = str(member.xpath("string(legislator/@state)"))
        party = str(member.xpath("string(legislator/@party)"))
        vote_cast = str(member.xpath("string(vote)"))
        bioguideid = str(member.xpath("string(legislator/@name-id)"))
        add_vote(
            vote_cast, {
                "id": bioguideid,
                "state": state,
                "party": party,
                "display_name": display_name,
            })

    # Through the 107th Congress and sporadically in more recent data, the bioguide field
    # is not present. Look up the Members' bioguide IDs by name/state/party/date. This works
    # reasonably well, but there are many gaps. When there's a gap, it raises an exception
    # and the file is not saved.
    #
    # Take into account that the vote may list both a "Smith" and a "Smith, John". Resolve
    # "Smith" by process of elimination, i.e. he must not be whoever "Smith, John" resolved
    # to. To do that, process the voters from longest specified display name to shortest.
    #
    # One example of a sporadic case is 108th Congress, 2nd session (2004), votes 405 through
    # 544, where G.K. Butterfield's bioguide ID is 000000. It should have been B001251.
    # See https://github.com/unitedstates/congress/issues/46.

    seen_ids = set()
    all_voters = sum(vote["votes"].values(), [])
    all_voters.sort(key=lambda v: len(v["display_name"]),
                    reverse=True)  # process longer names first
    for v in all_voters:
        if v["id"] not in ("", "0000000"):
            continue

        # here are wierd cases from h610-103.1993 that confound our name lookup since it has the wrong state abbr
        if v["state"] == "XX":
            for st in ("PR", "AS", "GU", "VI", "DC"):
                if v["display_name"].endswith(" (%s)" % st):
                    v["state"] = st

        # get the last name without the state abbreviation in parenthesis, if it is present
        display_name = v["display_name"].strip()
        ss = " (%s)" % v["state"]
        if display_name.endswith(ss):
            display_name = display_name[:-len(ss)].strip()

        # wrong party in upstream data
        if vote["vote_id"] == "h2-106.1999" and display_name == "Hastert":
            v["id"] = "H000323"
            continue

        # dead man recorded as Not Voting (he died the day before, so none of our roles match the vote date)
        if vote["vote_id"] == "h306-106.1999" and display_name == "Brown" and v[
                "state"] == "CA":
            v["id"] = "B000918"
            continue

        # look up ID
        v["id"] = utils.lookup_legislator(vote["congress"],
                                          "rep",
                                          display_name,
                                          v["state"],
                                          v["party"],
                                          vote["date"],
                                          "bioguide",
                                          exclude=seen_ids)

        if v["id"] == None:
            logging.error(
                "[%s] Missing bioguide ID and name lookup failed for %s (%s-%s on %s)"
                % (vote["vote_id"], display_name, v["state"], v["party"],
                   vote["date"]))
            raise Exception("No bioguide ID for %s (%s-%s)" %
                            (display_name, v["state"], v["party"]))
        else:
            if vote["congress"] > 107:
                logging.warn(
                    "[%s] Used name lookup for %s because bioguide ID was missing."
                    % (vote["vote_id"], v["display_name"]))
            seen_ids.add(v["id"])