def write_row(bill, sponsor, sponsor_type, sponsor_date): w.writerow([ bill.congress, bill.display_number_no_congress_number, bill.title_no_number.encode("utf8"), bill.sponsor_role.party, "https://www.govtrack.us" + bill.get_absolute_url(), sponsor_type, sponsor.id, get_person_name(sponsor, firstname_position='before', show_district=True, show_party=True, firstname_style="nickname").encode("utf8"), get_person_name(sponsor, firstname_position='after', show_district=True, show_party=True, show_title=False, firstname_style="nickname").encode("utf8"), sponsor.role.party, sponsor_date.isoformat(), ])
def bill_widget(request, congress, type_slug, number): bill = load_bill_from_url(congress, type_slug, number) from person.name import get_person_name if bill.sponsor: bill.sponsor.role = bill.sponsor_role # for rending name sponsor_name = None if not bill.sponsor else \ get_person_name(bill.sponsor, firstname_position='before', show_suffix=True) def get_text_info(): from billtext import load_bill_text try: return load_bill_text(bill, None, mods_only=True) except IOError: return None return { "SITE_ROOT_URL": settings.SITE_ROOT_URL, "bill": bill, "congressdates": get_congress_dates(bill.congress), "subtitle": get_secondary_bill_title(bill, bill.titles), "sponsor_name": sponsor_name, "current": bill.congress == CURRENT_CONGRESS, "dead": bill.congress != CURRENT_CONGRESS and bill.current_status not in BillStatus.final_status_obvious, "text": get_text_info, }
def bill_details(request, congress, type_slug, number): if type_slug.isdigit(): bill_type = type_slug else: try: bill_type = BillType.by_slug(type_slug) except BillType.NotFound: raise Http404("Invalid bill type: " + type_slug) bill = get_object_or_404(Bill, congress=congress, bill_type=bill_type, number=number) from person.name import get_person_name sponsor_name = None if not bill.sponsor else \ get_person_name(bill.sponsor, role_date=bill.introduced_date, firstname_position='before', show_suffix=True) def get_reintroductions(): reintro_prev = None reintro_next = None for reintro in bill.find_reintroductions(): if reintro.congress < bill.congress: reintro_prev = reintro if reintro.congress > bill.congress and not reintro_next: reintro_next = reintro return reintro_prev, reintro_next def get_text_info(): from billtext import load_bill_text try: return load_bill_text(bill, None, mods_only=True) except IOError: return None return { 'bill': bill, "congressdates": get_congress_dates(bill.congress), "subtitle": get_secondary_bill_title(bill, bill.titles), "sponsor_name": sponsor_name, "reintros": get_reintroductions, # defer so we can use template caching "current": bill.congress == CURRENT_CONGRESS, "dead": bill.congress != CURRENT_CONGRESS and bill.current_status not in BillStatus.final_status_obvious, "feed": Feed.BillFeed(bill), "text": get_text_info, }
def handle(self, *args, **options): # get all calls calls = list(CallLog.objects.all() .filter(position__position__issue__bills__id__gt=0) # only calls on bills, since we had a few non-bill calls at the beginning .exclude(user__email__endswith="@govtrack.us").exclude(user__email__endswith="@occams.info") # no testing calls by me .order_by('created') ) # filter - take only calls with recordings calls = filter(lambda call : call.log.get("finished", {}).get("RecordingUrl"), calls) ## shuffle so new anonymous ID assignments are random #shuffle(calls) # write out w = csv.writer(sys.stdout) w.writerow([ "call_id", "call_date", "call_duration", # "recording_url", # !!! not-anonymized "caller_id", "caller_account_created", "caller_district", "caller_areacode", "caller_areacode_city", "caller_areacode_state", "topic_id", "topic_name", "topic_link", "position_id", "position_name", "office_id", "office_type", "office_name", ]) def anonymize_user(user): global max_research_anon_key profile = user.userprofile() if profile.research_anon_key is None: # assign next available ID max_research_anon_key += 1 profile.research_anon_key = max_research_anon_key profile.save() return profile.research_anon_key for call in calls: if len(call.position.district) == 2: continue # data error in our very early data (one record?) # for making the right name for the called office call.target.person.role = call.target # write row w.writerow([ # call call.id, call.created.isoformat(), int(call.log["finished"]["RecordingDuration"][0]), # !!! this is not anonymous - call.log["finished"]["RecordingUrl"][0], # user anonymize_user(call.user), call.user.date_joined.isoformat(), # caller call.position.district, call.log["start"]["Called"][0][2:5], call.log["start"]["CalledCity"][0], call.log["start"]["CalledState"][0], # topic of call call.position.position.issue.first().id, call.position.position.issue.first().title.encode("utf8"), ";".join(["https://www.govtrack.us"+b.bill.get_absolute_url() for b in call.position.position.issue.first().bills.all()]), call.position.position.id, call.position.position.text.encode("utf8"), # target of call call.target.person.id, call.target.get_title(), get_person_name(call.target.person).encode("utf8"), ])
def lookup_reps(request): from django.contrib.humanize.templatetags.humanize import ordinal from person.name import get_person_name # Get the state and district from the query string. try: state = request.GET['state'] district = int(request.GET['district']) if state not in stateapportionment: raise Exception() except: return {} # Get the bill (optional) from the query string from bill.models import Bill try: bill = Bill.from_congressproject_id(request.GET["bill"]) except: bill = None # Helper to get relevant committee assignments. from committee.models import CommitteeMember, CommitteeMemberRole from committee.util import sort_members def mention_committees_once(committeeassignments): # The committee assignments have been sorted first by role (i.e. # committees that the person is the chair of come first) and then # by committee name (which also puts subcommittees after committees). # In order to be less verbose, only mention each full committee # once --- take the first in each mention. seen = set() for c in committeeassignments: if (c.committee in seen) or (c.committee.committee in seen): continue yield c if c.committee.committee is not None: seen.add(c.committee.committee) # add main committee else: seen.add(c.committee) # add this committee bounds = get_district_bounds(state, district) return { "state": { "name": statenames[state], "isTerritory": stateapportionment[state] == "T", }, "district": { "ordinal": ordinal(district) if district > 0 else "At Large", "bounds": { "center": { "latitude": bounds[0], "longitude": bounds[1] }, "zoom": bounds[2] } }, "members": [{ "id": p.id, "name": get_person_name(p, role_recent=True, firstname_position="before", show_title=True, show_party=False, show_district=False), "name_formal": p.current_role.get_title() + " " + p.lastname, "url": p.get_absolute_url(), "type": p.current_role.get_role_type_display(), "description": p.current_role.get_description(), "party": p.current_role.party, "photo_url": p.get_photo_url_50() if p.has_photo() else None, "contact_url": (p.current_role.extra or {}).get("contact_form") or p.current_role.website, "phone": p.current_role.phone, "website": p.current_role.website, "pronouns": { "him_her": p.him_her, "his_her": p.his_her, "he_she": p.he_she, }, "bill-status": { "cosponsor": p in bill.cosponsors.all(), "committee-assignments": [{ "committee": c.committee.fullname, "role": c.get_role_display() if c.role in ( CommitteeMemberRole.chair, CommitteeMemberRole.ranking_member, CommitteeMemberRole.vice_chair) else None, } for c in mention_committees_once( sort_members( CommitteeMember.objects.filter( person=p, committee__in=bill.committees.all())))] } if bill else None, } for p in list( Person.objects.filter(roles__current=True, roles__state=state, roles__role_type=RoleType.senator).order_by( 'roles__senator_rank')) + list( Person.objects.filter( roles__current=True, roles__state=state, roles__district=district, roles__role_type=RoleType.representative))] }
def get_vote_matrix(votes, filter_people=None, tqdm=lambda _: _): # Convert votes array to Vote instances with extra fields attached as instance fields. # votes is an array of tuples of the form # (Vote instance | Vote id, Vote slug, { extra dict info }) # or an array of just the first part of the tuple. def fetch_vote(item): if isinstance(item, tuple): id, extra = item else: id = item extra = {} # Fetch vote. if isinstance(id, int): vote = Vote.objects.get(id=id) elif isinstance(id, Vote): vote = id else: import re m = re.match(r"^(\d+)-(\w+)/([hs])(\d+)$", id) if not m: raise Http404(id) congress, session, chamber, number = m.groups() try: vote = load_vote(congress, session, chamber, number) except Http404: raise ValueError("Vote ID is not valid: " + id) # Add additional user-supplied fields. for k, v in extra.items(): setattr(vote, k, v) # Return return vote votes = [fetch_vote(item) for item in votes] # Compute totals by party, which yields a matrix like the matrix for voters # where the rows are parties and in each row the 'votes' key provides columns # for the votes. if not filter_people: party_totals = {} for i, vote in enumerate(votes): totals = vote.totals() for party, party_total in zip(totals['parties'], totals['party_counts']): pt = party_totals.setdefault( party, { "party": party, "total_votes": 0, "votes": [None] * len( votes ), # if this party didn't occur in prev votes, make sure we have an empty record }) pt["total_votes"] += party_total["total"] pt["votes"][i] = party_total party_totals = sorted(party_totals.values(), key=lambda value: -value['total_votes']) party_sort_order = [ party_total["party"] for party_total in party_totals ] # Is more than one chamber involved here? more_than_one_chamber = (len(set(v.chamber for v in votes)) > 1) # Compute the rows of the matrix. voters = {} for i, vote in enumerate(tqdm(votes)): for voter in vote.get_voters(filter_people=filter_people): if filter_people and voter.person not in filter_people: continue v = voters.setdefault( voter.person_id, { "person": voter.person, "total_plus": 0, "total_votes": 0, "votes": [None for _ in votes], }) v["votes"][i] = voter if voter.option.key == "+": v["total_plus"] += 1 if voter.option.key not in ("0", "P"): v["total_votes"] += 1 # Add name info at the moment of the vote. from person.name import get_person_name voter.person.role = voter.person_role voter.person.role.party = voter.party # party at this moment v["votes"][i].person_name = get_person_name( voter.person, firstname_position='after', show_district=True, show_title=False, show_type=more_than_one_chamber, show_party=False) # Choose one name & party & state-district (for sort). for voter in voters.values(): names = set(v.person_name for v in voter["votes"] if v is not None) if len(names) == 1: voter["person_name"] = list(names)[0] else: voter["person_name"] = get_person_name( voter["person"], firstname_position='after', show_district=False, show_title=False, show_type=more_than_one_chamber, show_party=False) parties = set(v.party for v in voter["votes"] if v is not None) if len(parties) == 1: voter["party"] = list(parties)[0] voter["party_order"] = party_sort_order.index(voter["party"]) roles = set( (v.person_role.state, str(v.person_role.role_type), str(v.person_role.senator_rank), ("%02d" % v.person_role.district if v.person_role.district else "")) for v in voter["votes"] if v is not None) if len(roles) == 1: voter["state_district"] = "-".join(list(roles)[0]) # Default sort order. voters = sorted(voters.values(), key=lambda value: value['person_name']) return votes, party_totals if not filter_people else None, voters
def person_name(p, when): p.role = p.get_role_at_date(when) # set for get_person_name return get_person_name(p).encode("utf8")
def bill_details(request, congress, type_slug, number): bill = load_bill_from_url(congress, type_slug, number) from person.name import get_person_name sponsor_name = None if not bill.sponsor else \ get_person_name(bill.sponsor, role_date=bill.introduced_date, firstname_position='before', show_suffix=True) def get_reintroductions(): reintro_prev = None reintro_next = None for reintro in bill.find_reintroductions(): if reintro.congress < bill.congress: reintro_prev = reintro if reintro.congress > bill.congress and not reintro_next: reintro_next = reintro return reintro_prev, reintro_next def get_text_info(): from models import USCSection from billtext import load_bill_text from search import parse_slip_law_number import re try: metadata = load_bill_text(bill, None, mods_only=True) # do interesting stuff with citations if "citations" in metadata and not settings.DEBUG: slip_laws = [] statutes = [] usc = { } other = [] usc_other = USCSection(name="Other Citations", ordering=99999) for cite in metadata["citations"]: if cite["type"] == "slip_law": slip_laws.append(cite) cite["bill"] = parse_slip_law_number(cite["text"]) elif cite["type"] == "statutes_at_large": statutes.append(cite) elif cite["type"] in ("usc-section", "usc-chapter"): # Build a tree of title-chapter-...-section nodes so we can # display the citations in context. try: sec_obj = USCSection.objects.get(citation=cite["key"]) except: # USCSection.DoesNotExist and MultipleObjectsReturned both possible # create a fake entry for the sake of output # the 'id' field is set to make these objects properly hashable sec_obj = USCSection(id=cite["text"], name=cite["text"], parent_section=usc_other) if "range_to_section" in cite: sec_obj.range_to_section = cite["range_to_section"] # recursively go up to the title path = [sec_obj] so = sec_obj while so.parent_section: so = so.parent_section path.append(so) # build a link to LII if cite["type"] == "usc-section": cite_link = "http://www.law.cornell.edu/uscode/text/" + cite["title"] if cite["section"]: cite_link += "/" + cite["section"] if cite["paragraph"]: cite_link += "#" + "_".join(re.findall(r"\(([^)]+)\)", cite["paragraph"])) elif cite["type"] == "usc-chapter": cite_link = "http://www.law.cornell.edu/uscode/text/" + cite["title"] + "/" + "/".join( (so.level_type + "-" + so.number) for so in reversed(path[:-1]) ) sec_obj.link = cite_link # now pop off from the path to put the node at the right point in a tree container = usc while path: p = path.pop(-1) if p not in container: container[p] = { } container = container[p] else: other.append(cite) slip_laws.sort(key = lambda x : (x["congress"], x["number"])) # restructure data format def ucfirst(s): return s[0].upper() + s[1:] def rebuild_usc_sec(seclist, indent=0): ret = [] seclist = sorted(seclist.items(), key=lambda x : x[0].ordering) for sec, subparts in seclist: ret.append({ "text": (ucfirst(sec.level_type + ((" " + sec.number) if sec.number else "") + (": " if sec.name else "")) if sec.level_type else "") + (sec.name_recased if sec.name else ""), "link": getattr(sec, "link", None), "range_to_section": getattr(sec, "range_to_section", None), "indent": indent, }) ret.extend(rebuild_usc_sec(subparts, indent=indent+1)) return ret usc = rebuild_usc_sec(usc) metadata["citations"] = { "slip_laws": slip_laws, "statutes": statutes, "usc": usc, "other": other, "count": len(slip_laws)+len(statutes)+len(usc)+len(other) } return metadata except IOError: return None return { 'bill': bill, "congressdates": get_congress_dates(bill.congress), "subtitle": get_secondary_bill_title(bill, bill.titles), "sponsor_name": sponsor_name, "reintros": get_reintroductions, # defer so we can use template caching "current": bill.congress == CURRENT_CONGRESS, "dead": bill.congress != CURRENT_CONGRESS and bill.current_status not in BillStatus.final_status_obvious, "feed": Feed.BillFeed(bill), "text": get_text_info, "care2_category_id": { 5816: '793', # Agriculture and Food=>Health 5840: '789', # Animals=>Animal Welfare 5996: '794', # Civil Rights=>Human Rights 5991: '791', # Education=>Education 6021: '792', # Energy=>Environment & Wildlife 6038: '792', # Environmental Protection=>Environment & Wildlife 6053: '793', # Families=>Health 6130: '793', # Health=>Health 6206: '794', # Immigration=>Human Rights 6279: '792', # Public Lands/Natural Resources=>Environment & Wildlife 6321: '791', # Social Sciences=>Education 6328: '793', # Social Welfare => Health }.get(bill.get_top_term_id(), '795') # fall back to Politics category }
def person_name(id, when): p = Person.objects.get(id=id) p.role = p.get_role_at_date(when) # set for get_person_name return get_person_name(p)
def lookup_reps(request): from django.contrib.humanize.templatetags.humanize import ordinal from person.name import get_person_name # Get the state and district from the query string. try: state = request.GET['state'] district = int(request.GET['district']) if state not in stateapportionment: raise Exception() except: return { } # Get the bill (optional) from the query string from bill.models import Bill try: bill = Bill.from_congressproject_id(request.GET["bill"]) except: bill = None # Helper to get relevant committee assignments. from committee.models import CommitteeMember, CommitteeMemberRole from committee.util import sort_members def mention_committees_once(committeeassignments): # The committee assignments have been sorted first by role (i.e. # committees that the person is the chair of come first) and then # by committee name (which also puts subcommittees after committees). # In order to be less verbose, only mention each full committee # once --- take the first in each mention. seen = set() for c in committeeassignments: if (c.committee in seen) or (c.committee.committee in seen): continue yield c if c.committee.committee is not None: seen.add(c.committee.committee) # add main committee else: seen.add(c.committee) # add this committee bounds = get_district_bounds(state, district) return { "state": { "name": statenames[state], "isTerritory": stateapportionment[state] == "T", }, "district": { "ordinal": ordinal(district) if district > 0 else "At Large", "bounds": { "center": { "latitude": bounds[0], "longitude": bounds[1] }, "zoom": bounds[2] } }, "members": [ { "id": p.id, "name": get_person_name(p, role_recent=True, firstname_position="before", show_title=True, show_party=False, show_district=False), "name_formal": p.current_role.get_title() + " " + p.lastname, "url": p.get_absolute_url(), "type": p.current_role.get_role_type_display(), "description": p.current_role.get_description(), "party": p.current_role.party, "photo_url": p.get_photo_url_50() if p.has_photo() else None, "contact_url": (p.current_role.extra or {}).get("contact_form") or p.current_role.website, "phone": p.current_role.phone, "website": p.current_role.website, "pronouns": { "him_her": p.him_her, "his_her": p.his_her, "he_she": p.he_she, }, "bill-status": { "cosponsor": p in bill.cosponsors.all(), "committee-assignments": [ { "committee": c.committee.fullname, "role": c.get_role_display() if c.role in (CommitteeMemberRole.chair, CommitteeMemberRole.ranking_member, CommitteeMemberRole.vice_chair) else None, } for c in mention_committees_once( sort_members( CommitteeMember.objects.filter(person=p, committee__in=bill.committees.all()))) ] } if bill else None, } for p in list(Person.objects.filter(roles__current=True, roles__state=state, roles__role_type=RoleType.senator) .order_by('roles__senator_rank')) + list(Person.objects.filter(roles__current=True, roles__state=state, roles__district=district, roles__role_type=RoleType.representative)) ] }
def vote_comparison_table(request, table_id, table_slug): # Validate URL. if int(table_id) != 1: raise Http404() if table_slug != "trump-nominations": return HttpResponseRedirect( "/congress/votes/compare/1/trump-nominations") # Get votes to show. votes = [ ("115-2017/s29", { "title": "James Mattis to be Secretary of Defense" }), ("115-2017/s30", { "title": "John F. Kelly to be Secretary of Homeland Security" }), ("115-2017/s32", { "title": "Mike Pompeo to be Director of the Central Intelligence Agency" }), ("115-2017/s33", { "title": "Nikki R. Haley to be the Ambassador to the United Nations" }), ] voters = None # Fetch votes. def fetch_vote(id, extra): # Fetch vote. if isinstance(id, int): vote = Vote.objects.get(id=id) else: import re m = re.match(r"^(\d+)-(\w+)/([hs])(\d+)$", id) if not m: raise Http404(id) congress, session, chamber, number = m.groups() try: vote = load_vote(congress, session, chamber, number) except Http404: raise ValueError("Vote ID is not valid: " + id) # Add additional user-supplied fields. for k, v in extra.items(): setattr(vote, k, v) # Return return vote votes = [fetch_vote(id, extra) for id, extra in votes] # Compute totals by party. party_totals = {} for vote in votes: totals = vote.totals() for party, party_total in zip(totals['parties'], totals['party_counts']): pt = party_totals.setdefault(party, { "party": party, "total_votes": 0, "votes": [], }) pt["total_votes"] += party_total["total"] pt["votes"].append(party_total) party_totals = sorted(party_totals.values(), key=lambda value: -value['total_votes']) party_sort_order = [party_total["party"] for party_total in party_totals] # Is more than one chamber in involved here? more_than_one_chamber = (len(set(v.chamber for v in votes)) > 1) # Pull voters. voters = {} for i, vote in enumerate(votes): for voter in vote.get_voters(): v = voters.setdefault( voter.person_id, { "person": voter.person, "total_plus": 0, "total_votes": 0, "votes": [None for _ in votes], }) v["votes"][i] = voter if voter.option.key == "+": v["total_plus"] += 1 if voter.option.key not in ("0", "P"): v["total_votes"] += 1 # Add name info at the moment of the vote. from person.name import get_person_name voter.person.role = voter.person_role voter.person.role.party = voter.party # party at this moment v["votes"][i].person_name = get_person_name( voter.person, firstname_position='after', show_district=True, show_title=False, show_type=more_than_one_chamber, show_party=False) # Choose one name & party & state-district (for sort). for voter in voters.values(): names = set(v.person_name for v in voter["votes"] if v is not None) if len(names) == 1: voter["person_name"] = list(names)[0] else: voter["person_name"] = get_person_name( voter["person"], firstname_position='after', show_district=False, show_title=False, show_type=more_than_one_chamber, show_party=False) parties = set(v.party for v in voter["votes"] if v is not None) if len(parties) == 1: voter["party"] = list(parties)[0] voter["party_order"] = party_sort_order.index(voter["party"]) roles = set( (v.person_role.state, str(v.person_role.role_type), str(v.person_role.senator_rank), ("%02d" % v.person_role.district if v.person_role.district else "")) for v in voter["votes"] if v is not None) if len(roles) == 1: voter["state_district"] = "-".join(list(roles)[0]) # Default sort order. voters = sorted(voters.values(), key=lambda value: value['person_name']) return { "title": "Key Trump Nominations", "description": "Senate votes on key Trump nominations.", "votes": votes, "party_totals": party_totals, "voters": voters, "col_width_pct": int(round(100 / (len(votes) + 1))), }
def bill_details(request, congress, type_slug, number): if type_slug.isdigit(): bill_type = type_slug else: try: bill_type = BillType.by_slug(type_slug) except BillType.NotFound: raise Http404("Invalid bill type: " + type_slug) bill = get_object_or_404(Bill, congress=congress, bill_type=bill_type, number=number) from person.name import get_person_name sponsor_name = None if not bill.sponsor else \ get_person_name(bill.sponsor, role_date=bill.introduced_date, firstname_position='before', show_suffix=True) def get_reintroductions(): reintro_prev = None reintro_next = None for reintro in bill.find_reintroductions(): if reintro.congress < bill.congress: reintro_prev = reintro if reintro.congress > bill.congress and not reintro_next: reintro_next = reintro return reintro_prev, reintro_next def get_text_info(): from models import USCSection from billtext import load_bill_text from search import parse_slip_law_number import re try: metadata = load_bill_text(bill, None, mods_only=True) # do interesting stuff with citations if "citations" in metadata: slip_laws = [] statutes = [] usc = { } other = [] usc_other = USCSection(name="Other Citations", ordering=99999) for cite in metadata["citations"]: if cite["type"] == "slip_law": slip_laws.append(cite) cite["bill"] = parse_slip_law_number(cite["text"]) elif cite["type"] == "statutes_at_large": statutes.append(cite) elif cite["type"] == "usc": # build a normalized citation and a link to LII cite_norm = "usc/" + cite["title"] cite_link = "http://www.law.cornell.edu/uscode/text/" + cite["title"] if cite["section"]: cite_link += "/" + cite["section"] cite_norm += "/" + cite["section"] if cite["paragraph"]: cite_link += "#" + "_".join(re.findall(r"\(([^)]+)\)", cite["paragraph"])) # Build a tree of title-chapter-...-section nodes so we can # display the citations in context. try: sec_obj = USCSection.objects.get(citation=cite_norm) except: # USCSection.DoesNotExist and MultipleObjectsReturned both possible # the 'id' field is set to make these objects properly hashable sec_obj = USCSection(id=cite["text"], name=cite["text"], parent_section=usc_other) sec_obj.link = cite_link if "range_to_section" in cite: sec_obj.range_to_section = cite["range_to_section"] # recursively go up to the title path = [sec_obj] while sec_obj.parent_section: sec_obj = sec_obj.parent_section path.append(sec_obj) # now pop off from the path to put the node at the right point in a tree container = usc while path: p = path.pop(-1) if p not in container: container[p] = { } container = container[p] else: other.append(cite) slip_laws.sort(key = lambda x : (x["congress"], x["number"])) # restructure data format def ucfirst(s): return s[0].upper() + s[1:] def rebuild_usc_sec(seclist, indent=0): ret = [] seclist = sorted(seclist.items(), key=lambda x : x[0].ordering) for sec, subparts in seclist: ret.append({ "text": (ucfirst(sec.level_type + ((" " + sec.number) if sec.number else "") + (": " if sec.name else "")) if sec.level_type else "") + (sec.name if sec.name else ""), "link": getattr(sec, "link", None), "range_to_section": getattr(sec, "range_to_section", None), "indent": indent, }) ret.extend(rebuild_usc_sec(subparts, indent=indent+1)) return ret usc = rebuild_usc_sec(usc) metadata["citations"] = { "slip_laws": slip_laws, "statutes": statutes, "usc": usc, "other": other, "count": len(slip_laws)+len(statutes)+len(usc)+len(other) } return metadata except IOError: return None return { 'bill': bill, "congressdates": get_congress_dates(bill.congress), "subtitle": get_secondary_bill_title(bill, bill.titles), "sponsor_name": sponsor_name, "reintros": get_reintroductions, # defer so we can use template caching "current": bill.congress == CURRENT_CONGRESS, "dead": bill.congress != CURRENT_CONGRESS and bill.current_status not in BillStatus.final_status_obvious, "feed": Feed.BillFeed(bill), "text": get_text_info, }
def get_vote_matrix(votes, filter_people=None, tqdm=lambda _ : _): # Convert votes array to Vote instances with extra fields attached as instance fields. # votes is an array of tuples of the form # (Vote instance | Vote id, Vote slug, { extra dict info }) # or an array of just the first part of the tuple. def fetch_vote(item): if isinstance(item, tuple): id, extra = item else: id = item extra = { } # Fetch vote. if isinstance(id, int): vote = Vote.objects.get(id=id) elif isinstance(id, Vote): vote = id else: import re m = re.match(r"^(\d+)-(\w+)/([hs])(\d+)$", id) if not m: raise Http404(id) congress, session, chamber, number = m.groups() try: vote = load_vote(congress, session, chamber, number) except Http404: raise ValueError("Vote ID is not valid: " + id) # Add additional user-supplied fields. for k, v in extra.items(): setattr(vote, k, v) # Return return vote votes = [fetch_vote(item) for item in votes] # Compute totals by party, which yields a matrix like the matrix for voters # where the rows are parties and in each row the 'votes' key provides columns # for the votes. if not filter_people: party_totals = { } for i, vote in enumerate(votes): totals = vote.totals() for party, party_total in zip(totals['parties'], totals['party_counts']): pt = party_totals.setdefault(party, { "party": party, "total_votes": 0, "votes": [None] * len(votes), # if this party didn't occur in prev votes, make sure we have an empty record }) pt["total_votes"] += party_total["total"] pt["votes"][i] = party_total party_totals = sorted(party_totals.values(), key = lambda value : -value['total_votes']) party_sort_order = [party_total["party"] for party_total in party_totals] # Is more than one chamber involved here? more_than_one_chamber = (len(set(v.chamber for v in votes)) > 1) # Compute the rows of the matrix. voters = { } for i, vote in enumerate(tqdm(votes)): for voter in vote.get_voters(filter_people=filter_people): if filter_people and voter.person not in filter_people: continue v = voters.setdefault(voter.person_id, { "person": voter.person, "total_plus": 0, "total_votes": 0, "votes": [None for _ in votes], }) v["votes"][i] = voter if voter.option.key == "+": v["total_plus"] += 1 if voter.option.key not in ("0", "P"): v["total_votes"] += 1 # Add name info at the moment of the vote. from person.name import get_person_name voter.person.role = voter.person_role voter.person.role.party = voter.party # party at this moment v["votes"][i].person_name = get_person_name(voter.person, firstname_position='after', show_district=True, show_title=False, show_type=more_than_one_chamber, show_party=False) # Choose one name & party & state-district (for sort). for voter in voters.values(): names = set(v.person_name for v in voter["votes"] if v is not None) if len(names) == 1: voter["person_name"] = list(names)[0] else: voter["person_name"] = get_person_name(voter["person"], firstname_position='after', show_district=False, show_title=False, show_type=more_than_one_chamber, show_party=False) parties = set(v.party for v in voter["votes"] if v is not None) if len(parties) == 1: voter["party"] = list(parties)[0] voter["party_order"] = party_sort_order.index(voter["party"]) roles = set((v.person_role.state, str(v.person_role.role_type), str(v.person_role.senator_rank), ("%02d" % v.person_role.district if v.person_role.district else "")) for v in voter["votes"] if v is not None) if len(roles) == 1: voter["state_district"] = "-".join(list(roles)[0]) # Default sort order. voters = sorted(voters.values(), key = lambda value : value['person_name']) return votes, party_totals if not filter_people else None, voters
def person_name(self): # don't need title because it's implicit from the bill type from person.name import get_person_name return get_person_name(self.person, role_date=self.joined, firstname_position="after", show_title=False)