Skip to content

Commit

Permalink
Merge pull request #719 from jmcarp/feature/cycle-filter
Browse files Browse the repository at this point in the history
Feature/cycle filter
arowla committed May 11, 2015
2 parents df36f84 + 658eedb commit 9d3ad81
Showing 11 changed files with 176 additions and 143 deletions.
2 changes: 1 addition & 1 deletion data/sql_updates/create_committee_detail_view.sql
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ from dimcmte
left join (
select
cmte_sk,
array_agg(distinct(rpt_yr + rpt_yr % 2)) as cycles
array_agg(distinct(rpt_yr + rpt_yr % 2))::int[] as cycles
from dimcmteproperties
where rpt_yr >= :START_YEAR
group by cmte_sk
2 changes: 1 addition & 1 deletion data/sql_updates/create_committees_view.sql
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ from dimcmte
left join (
select
cmte_sk,
array_agg(distinct(rpt_yr + rpt_yr % 2)) as cycles
array_agg(distinct(rpt_yr + rpt_yr % 2))::int[] as cycles
from dimcmteproperties
where rpt_yr >= :START_YEAR
group by cmte_sk
7 changes: 0 additions & 7 deletions webservices/common/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from datetime import datetime
from flask.ext.restful import reqparse
from os.path import dirname
from os.path import join as join_path
@@ -16,12 +15,6 @@ def merge_dicts(x, y):
return z


def default_year():
year = datetime.now().year
years = [str(y) for y in range(year+1, year-4, -1)]
return ','.join(years)


def natural_number(n):
result = int(n)
if result < 1:
61 changes: 26 additions & 35 deletions webservices/resources/candidates.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from flask.ext.restful import Resource, reqparse, fields, marshal_with, inputs, marshal
from webservices.common.models import db, Candidate, CandidateDetail, Committee, CandidateCommitteeLink, CandidateHistory
from webservices.common.util import default_year, Pagination
from webservices.common.util import Pagination
from sqlalchemy.sql import text, or_
from sqlalchemy import extract

@@ -13,6 +13,7 @@
'district': fields.String,
'active_through': fields.Integer,
'election_years': fields.List(fields.Integer),
'cycles': fields.List(fields.Integer),
'incumbent_challenge_full': fields.String,
'incumbent_challenge': fields.String,
'office_full': fields.String,
@@ -87,19 +88,18 @@
class CandidateList(Resource):
parser = reqparse.RequestParser()
parser.add_argument('q', type=str, help='Text to search all fields for')
parser.add_argument('candidate_id', type=str, help="Candidate's FEC ID")
parser.add_argument('candidate_id', type=str, action='append', help="Candidate's FEC ID")
parser.add_argument('fec_id', type=str, help="Candidate's FEC ID")
parser.add_argument('page', type=inputs.natural, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=inputs.natural, default=20, help='The number of results returned per page. Defaults to 20.')
parser.add_argument('name', type=str, help="Candidate's name (full or partial)")
parser.add_argument('office', type=str, help='Governmental office candidate runs for')
parser.add_argument('state', type=str, help='U. S. State candidate is registered in')
parser.add_argument('party', type=str, help="Three letter code for the party under which a candidate ran for office")
parser.add_argument('year', type=str, default=default_year(), dest='election_year', help="Fileter records to only those that were applicable to a given year")
parser.add_argument('district', type=str, help='Two digit district number')
parser.add_argument('candidate_status', type=str, help='One letter code explaining if the candidate is a present, future or past candidate')
parser.add_argument('incumbent_challenge', type=str, help='One letter code explaining if the candidate is an incumbent, a challenger, or if the seat is open.')

parser.add_argument('office', type=str, action='append', help='Governmental office candidate runs for')
parser.add_argument('state', type=str, action='append', help='U. S. State candidate is registered in')
parser.add_argument('party', type=str, action='append', help="Three letter code for the party under which a candidate ran for office")
parser.add_argument('cycle', type=int, action='append', help='Filter records to only those that were applicable to a given election cycle')
parser.add_argument('district', type=str, action='append', help='Two digit district number')
parser.add_argument('candidate_status', type=str, action='append', help='One letter code explaining if the candidate is a present, future or past candidate')
parser.add_argument('incumbent_challenge', type=str, action='append', help='One letter code explaining if the candidate is an incumbent, a challenger, or if the seat is open.')

@marshal_with(candidate_list_fields)
def get(self, **kwargs):
@@ -138,17 +138,14 @@ def get_candidates(self, args, page_num, per_page):
for argname in ['candidate_id', 'candidate_status', 'district', 'incumbent_challenge', 'office', 'party', 'state']:
if args.get(argname):
# this is not working and doesn't look like it would work for _short
if ',' in args[argname]:
candidates = candidates.filter(getattr(Candidate, argname).in_(args[argname].split(',')))
else:
candidates = candidates.filter_by(**{argname: args[argname]})

candidates = candidates.filter(getattr(Candidate, argname).in_(args[argname]))

if args.get('name'):
candidates = candidates.filter(Candidate.name.ilike('%{}%'.format(args['name'])))

if args.get('election_year') and args['election_year'] != '*':
candidates = candidates.filter(Candidate.election_years.overlap([int(x) for x in args['election_year'].split(',')]))
# TODO(jmcarp) Reintroduce year filter pending accurate `load_date` and `expire_date` values
if args['cycle']:
candidates = candidates.filter(Candidate.cycles.overlap(args['cycle']))

count = candidates.count()

@@ -161,13 +158,13 @@ class CandidateView(Resource):
parser = reqparse.RequestParser()
parser.add_argument('page', type=inputs.natural, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=inputs.natural, default=20, help='The number of results returned per page. Defaults to 20.')
parser.add_argument('office', type=str, help='Governmental office candidate runs for')
parser.add_argument('state', type=str, help='U. S. State candidate is registered in')
parser.add_argument('party', type=str, help="Three letter code for the party under which a candidate ran for office")
parser.add_argument('year', type=str, help="See records pertaining to a particular year.")
parser.add_argument('district', type=str, help='Two digit district number')
parser.add_argument('candidate_status', type=str, help='One letter code explaining if the candidate is a present, future or past candidate')
parser.add_argument('incumbent_challenge', type=str, help='One letter code explaining if the candidate is an incumbent, a challenger, or if the seat is open.')
parser.add_argument('office', type=str, action='append', help='Governmental office candidate runs for')
parser.add_argument('state', type=str, action='append', help='U. S. State candidate is registered in')
parser.add_argument('party', type=str, action='append', help="Three letter code for the party under which a candidate ran for office")
parser.add_argument('cycle', type=int, action='append', help='Filter records to only those that were applicable to a given election cycle')
parser.add_argument('district', type=str, action='append', help='Two digit district number')
parser.add_argument('candidate_status', type=str, action='append', help='One letter code explaining if the candidate is a present, future or past candidate')
parser.add_argument('incumbent_challenge', type=str, action='append', help='One letter code explaining if the candidate is an incumbent, a challenger, or if the seat is open.')


def get(self, **kwargs):
@@ -209,17 +206,11 @@ def get_candidate(self, args, page_num, per_page, candidate_id, committee_id):
for argname in ['candidate_id', 'candidate_status', 'district', 'incumbent_challenge', 'office', 'party', 'state']:
if args.get(argname):
# this is not working and doesn't look like it would work for _short
if ',' in args[argname]:
candidates = candidates.filter(getattr(CandidateDetail, argname).in_(args[argname].split(',')))
else:
candidates = candidates.filter_by(**{argname: args[argname]})

# To support '*' across all endpoints
if args.get('year') and args['year'] != '*':
# before expiration
candidates = candidates.filter(or_(extract('year', CandidateDetail.expire_date) >= int(args['year']), CandidateDetail.expire_date == None))
# after origination
candidates = candidates.filter(extract('year', CandidateDetail.load_date) <= int(args['year']))
candidates = candidates.filter(getattr(CandidateDetail, argname).in_(args[argname]))

# TODO(jmcarp) Reintroduce year filter pending accurate `load_date` and `expire_date` values
if args['cycle']:
candidates = candidates.filter(CandidateDetail.cycles.overlap(args['cycle']))

count = candidates.count()

110 changes: 49 additions & 61 deletions webservices/resources/committees.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask.ext.restful import Resource, reqparse, fields, marshal_with, inputs, marshal
from webservices.common.models import db, Candidate, Committee, CandidateCommitteeLink, CommitteeDetail
from webservices.common.util import default_year, Pagination
from sqlalchemy.sql import text, or_
from webservices.common.util import Pagination
from sqlalchemy.sql import text, or_, and_
from sqlalchemy import extract
from datetime import date

@@ -94,35 +94,50 @@
}


def filter_year(model, query, years):
return query.filter(
or_(*[
and_(
or_(
extract('year', model.last_file_date) >= year,
model.last_file_date == None,
),
extract('year', model.first_file_date) <= year,
)
for year in years
])
) # noqa


class CommitteeList(Resource):
parser = reqparse.RequestParser()
parser.add_argument('q', type=str, help='Text to search all fields for')
parser.add_argument('committee_id', type=str, help="Committee's FEC ID")
parser.add_argument('candidate_id', type=str, help="Candidate's FEC ID")
parser.add_argument('state', type=str, help='Two digit U.S. State committee is registered in')
parser.add_argument('committee_id', type=str, action='append', help="Committee's FEC ID")
parser.add_argument('candidate_id', type=str, action='append', help="Candidate's FEC ID")
parser.add_argument('state', type=str, action='append', help='Two character U.S. State committee is registered in')
parser.add_argument('name', type=str, help="Committee's name (full or partial)")
parser.add_argument('page', type=int, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=int, default=20, help='The number of results returned per page. Defaults to 20.')
parser.add_argument('committee_type', type=str, help='The one-letter type code of the organization')
parser.add_argument('designation', type=str, help='The one-letter designation code of the organization')
parser.add_argument('organization_type', type=str, help='The one-letter code for the kind for organization')
parser.add_argument('party', type=str, help='Three letter code for party')
parser.add_argument('year', type=str, default=None, help='A year that the committee was active- (after original registration date but before expiration date.)')
parser.add_argument('committee_type', type=str, action='append', help='The one-letter type code of the organization')
parser.add_argument('designation', type=str, action='append', help='The one-letter designation code of the organization')
parser.add_argument('organization_type', type=str, action='append', help='The one-letter code for the kind for organization')
parser.add_argument('party', type=str, action='append', help='Three letter code for party')
parser.add_argument('year', type=int, action='append', help='A year that the committee was active- (after original registration date but before expiration date.)')
parser.add_argument('cycle', type=int, action='append', help='An election cycle that the committee was active- (after original registration date but before expiration date.)')
# not implemented yet
# parser.add_argument('expire_date', type=str, help='Date the committee registration expires')
# parser.add_argument('original_registration_date', type=str, help='Date of the committees first registered')

@marshal_with(committee_list_fields)
def get(self, **kwargs):
def get(self):

args = self.parser.parse_args(strict=True)
candidate_id = kwargs.get('id', args.get('candidate_id', None))

# pagination
page_num = args.get('page', 1)
per_page = args.get('per_page', 20)

count, committees = self.get_committees(args, page_num, per_page, candidate_id=candidate_id)
count, committees = self.get_committees(args, page_num, per_page)

page_data = Pagination(page_num, per_page, count)

@@ -135,12 +150,12 @@ def get(self, **kwargs):
return data


def get_committees(self, args, page_num, per_page, candidate_id=None):
def get_committees(self, args, page_num, per_page):

committees = Committee.query

if candidate_id:
committees = committees.filter(Committee.candidate_ids.overlap(candidate_id.split(',')))
if args['candidate_id']:
committees = committees.filter(Committee.candidate_ids.overlap(args['candidate_id']))

elif args.get('q'):
fulltext_qry = """SELECT cmte_sk
@@ -152,38 +167,18 @@ def get_committees(self, args, page_num, per_page, candidate_id=None):
committees = committees.filter(Committee.committee_key.in_(
db.session.query("cmte_sk").from_statement(text(fulltext_qry)).params(findme=findme)))


for argname in ['committee_id', 'designation', 'organization_type', 'state', 'party', 'committee_type']:
if args.get(argname):
if ',' in args[argname]:
committees = committees.filter(getattr(Committee, argname).in_(args[argname].split(',')))
else:
committees = committees.filter(getattr(Committee, argname)==args[argname])
committees = committees.filter(getattr(Committee, argname).in_(args[argname]))

if args.get('name'):
committees = committees.filter(Committee.name.ilike('%{}%'.format(args['name'])))

# default year filtering
if args.get('year') is None:
earliest_year = int(sorted(default_year().split(','))[0])
# still going or expired after the earliest year we are looking for
committees = committees.filter(
or_(
extract('year', Committee.last_file_date) >= earliest_year,
Committee.last_file_date == None,
)
) # noqa

# Should this handle a list of years to make it consistent with /candidate ?
elif args.get('year') and args['year'] != '*':
year = int(args['year'])
committees = committees.filter(
or_(
extract('year', Committee.last_file_date) >= year,
Committee.last_file_date == None,
),
extract('year', Committee.first_file_date) <= year,
) # noqa
if args['year']:
committees = filter_year(Committee, committees, args['year'])

if args['cycle']:
committees = committees.filter(Committee.cycles.overlap(args['cycle']))

count = committees.count()

@@ -195,11 +190,12 @@ class CommitteeView(Resource):
parser = reqparse.RequestParser()
parser.add_argument('page', type=int, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=int, default=20, help='The number of results returned per page. Defaults to 20.')
parser.add_argument('year', type=str, default=None, help='A year that the committee was active- (after original registration date but before expiration date.)')
parser.add_argument('year', type=int, action='append', help='A year that the committee was active- (after original registration date but before expiration date.)')
parser.add_argument('cycle', type=int, action='append', help='An election cycle that the committee was active- (after original registration date but before expiration date.)')
# useful for lookup by candidate id
parser.add_argument('designation', type=str, help='The one-letter designation code of the organization')
parser.add_argument('organization_type', type=str, help='The one-letter code for the kind for organization')
parser.add_argument('committee_type', type=str, help='The one-letter type code of the organization')
parser.add_argument('designation', type=str, action='append', help='The one-letter designation code of the organization')
parser.add_argument('organization_type', type=str, action='append', help='The one-letter code for the kind for organization')
parser.add_argument('committee_type', type=str, action='append', help='The one-letter type code of the organization')

def get(self, **kwargs):

@@ -243,21 +239,13 @@ def get_committee(self, args, page_num, per_page, committee_id, candidate_id):

for argname in ['designation', 'organization_type', 'committee_type']:
if args.get(argname):
if ',' in args[argname]:
committees = committees.filter(getattr(CommitteeDetail, argname).in_(args[argname].split(',')))
else:
committees = committees.filter(getattr(CommitteeDetail, argname)==args[argname])

# To support '*' across all endpoints
if args.get('year') and args['year'] != '*':
year = int(args['year'])
committees = committees.filter(
or_(
extract('year', CommitteeDetail.last_file_date) >= year,
CommitteeDetail.last_file_date == None,
),
extract('year', CommitteeDetail.first_file_date) <= year,
) # noqa
committees = committees.filter(getattr(CommitteeDetail, argname).in_(args[argname]))

if args['year']:
committees = filter_year(CommitteeDetail, committees, args['year'])

if args['cycle']:
committees = committees.filter(CommitteeDetail.cycles.overlap(args['cycle']))

count = committees.count()

11 changes: 7 additions & 4 deletions webservices/resources/reports.py
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ class CommitteeReports(BaseModel):
report_key = db.Column(db.BigInteger)
committee_id = db.Column(db.String(10))
cycle = db.Column(db.Integer)
report_year = db.Column(db.Integer)

beginning_image_number = db.Column(db.Integer)
cash_on_hand_beginning_period = db.Column(db.Integer)
@@ -490,8 +491,8 @@ class ReportsView(Resource):
parser = reqparse.RequestParser()
parser.add_argument('page', type=inputs.natural, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=inputs.natural, default=20, help='The number of results returned per page. Defaults to 20.')
# TODO: change to filter on report_year and add a separate filter for cycle
parser.add_argument('year', type=str, default='*', dest='cycle', help="Year in which a candidate runs for office")
parser.add_argument('year', type=int, action='append', help='Year in which a candidate runs for office')
parser.add_argument('cycle', type=int, action='append', help='Two-year election cycle in which a candidate runs for office')
parser.add_argument('fields', type=str, help='Choose the fields that are displayed')

def get(self, committee_id=None, committee_type=None):
@@ -539,8 +540,10 @@ def get_reports(self, committee_id, committee_type, args, page_num, per_page):
if committee_id is not None:
reports = reports.filter_by(committee_id=committee_id)

if args['cycle'] != '*':
reports = reports.filter(reports_class.cycle.in_(args['cycle'].split(',')))
if args['year']:
reports = reports.filter(reports_class.report_year.in_(args['year']))
if args['cycle']:
reports = reports.filter(reports_class.cycle.in_(args['cycle']))

count = reports.count()

6 changes: 3 additions & 3 deletions webservices/resources/totals.py
Original file line number Diff line number Diff line change
@@ -207,7 +207,7 @@ class TotalsView(Resource):
parser = reqparse.RequestParser()
parser.add_argument('page', type=inputs.natural, default=1, help='For paginating through results, starting at page 1')
parser.add_argument('per_page', type=inputs.natural, default=20, help='The number of results returned per page. Defaults to 20.')
parser.add_argument('year', type=str, default='*', dest='cycle', help="Year in which a candidate runs for office")
parser.add_argument('cycle', type=int, action='append', help='Two-year election cycle in which a candidate runs for office')
parser.add_argument('fields', type=str, help='Choose the fields that are displayed')

def get(self, **kwargs):
@@ -248,8 +248,8 @@ def get_totals(self, committee_id, totals_class, args, page_num, per_page):

totals = totals_class.query.filter_by(committee_id=committee_id)

if args['cycle'] != '*':
totals = totals.filter(totals_class.cycle.in_(args['cycle'].split(',')))
if args['cycle']:
totals = totals.filter(totals_class.cycle.in_(args['cycle']))

totals = totals.order_by(desc(totals_class.cycle))
return totals.paginate(page_num, per_page, True).items
17 changes: 11 additions & 6 deletions webservices/test_api.py
Original file line number Diff line number Diff line change
@@ -49,13 +49,18 @@ def test_full_text_no_results(self):
results = self._results(api.url_for(CandidateList, q='asdfasdf'))
self.assertEquals(results, [])

def test_year_filter(self):
factories.CandidateFactory(election_years=[1986, 1988])
factories.CandidateFactory(election_years=[2000, 2002])
results = self._results(api.url_for(CandidateList, year=1988))
def test_cycle_filter(self):
factories.CandidateFactory(cycles=[1986, 1988])
factories.CandidateFactory(cycles=[2000, 2002])
results = self._results(api.url_for(CandidateList, cycle=1988))
self.assertEqual(len(results), 1)
for r in results:
self.assertIn(1988, r['election_years'])
for result in results:
self.assertIn(1988, result['cycles'])
results = self._results(api.url_for(CandidateList, cycle=[1986, 2002]))
self.assertEqual(len(results), 2)
cycles = set([1986, 2002])
for result in results:
self.assertTrue(cycles.intersection(result['cycles']))

def test_per_page_defaults_to_20(self):
[factories.CandidateFactory() for _ in range(40)]
8 changes: 4 additions & 4 deletions webservices/tests/candidate_tests.py
Original file line number Diff line number Diff line change
@@ -117,19 +117,19 @@ def test_cand_filters(self):
factories.CandidateFactory(state='CA'),
factories.CandidateFactory(name='Obama'),
factories.CandidateFactory(party='DEM'),
factories.CandidateFactory(election_years=[2006]),
factories.CandidateFactory(cycles=[2006]),
factories.CandidateFactory(candidate_id='barlet'),
factories.CandidateFactory(candidate_id='ritchie'),
]

filter_fields = (
('office', 'H'),
('district', '00,02'),
('district', ['00', '02']),
('state', 'CA'),
('name', 'Obama'),
('party', 'DEM'),
('year', '2006'),
('candidate_id', 'bartlet,ritchie')
('cycle', '2006'),
('candidate_id', ['bartlet', 'ritchie'])
)

# checking one example from each field
20 changes: 10 additions & 10 deletions webservices/tests/committee_tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import urllib
import datetime
import functools

@@ -55,7 +56,7 @@ def test_filter_by_candidate_ids(self):
candidate1_committees = [factories.CommitteeFactory(candidate_ids=[candidate_ids[0]]) for _ in range(2)]
candidate2_committees = [factories.CommitteeFactory(candidate_ids=[candidate_ids[1]]) for _ in range(2)]
other_committees = [factories.CommitteeFactory() for _ in range(3)] # noqa
response = self._response(api.url_for(CommitteeList, candidate_id=','.join(candidate_ids)))
response = self._response(api.url_for(CommitteeList, candidate_id=candidate_ids))
self.assertEqual(
len(response['results']),
len(candidate1_committees) + len(candidate2_committees)
@@ -87,8 +88,8 @@ def test_committee_detail_fields(self):

def test_committee_search_double_committee_id(self):
committees = [factories.CommitteeFactory() for _ in range(2)]
ids = ','.join(each.committee_id for each in committees)
response = self._response(api.url_for(CommitteeList, committee_id=ids, year='*'))
ids = [each.committee_id for each in committees]
response = self._response(api.url_for(CommitteeList, committee_id=ids))
results = response['results']
self.assertEqual(len(results), 2)

@@ -136,10 +137,9 @@ def _check_filter(self, field, values, base_url, alt=None, **attrs):

# Assert that `len(values)` records are found for multi-valued search
# (e.g. field=value1,value2...valueN)
url = '{0}?{1}={2}'.format(
url = '{0}?{1}'.format(
base_url,
field,
','.join(str(each) for each in values),
urllib.parse.urlencode({field: values}, doseq=True)
)
results = self._results(url)
self.assertEqual(len(results), len(values))
@@ -159,12 +159,12 @@ def test_committee_filters(self):

# checking one example from each field
filter_fields = (
('committee_id', 'bartlet,ritchie'),
('state', 'CA,DC'),
('committee_id', ['bartlet', 'ritchie']),
('state', ['CA', 'DC']),
('name', 'Obama'),
('committee_type', 'S'),
('designation', 'P'),
('party', 'REP,DEM'),
('party', ['REP', 'DEM']),
('organization_type', 'C'),
)

@@ -251,5 +251,5 @@ def test_candidates_by_com(self):
candidate_key=candidate.candidate_key,
committee_id=committee_id,
)
results = self._results(api.url_for(CandidateView, committee_id=committee_id, year='*'))
results = self._results(api.url_for(CandidateView, committee_id=committee_id))
self.assertEquals(1, len(results))
75 changes: 64 additions & 11 deletions webservices/tests/report_tests.py
Original file line number Diff line number Diff line change
@@ -11,30 +11,83 @@ def _results(self, qry):
response = self._response(qry)
return response['results']

def _check_committee_ids(self, results, positives=None, negatives=None):
ids = [each['committee_id'] for each in results]
for positive in (positives or []):
self.assertIn(positive.committee_id, ids)
for negative in (negatives or []):
self.assertNotIn(negative.committee_id, ids)

def test_reports_by_committee_id(self):
committee = factories.CommitteeFactory(committee_type='P')
committee_id = committee.committee_id
committee_report = factories.ReportsPresidentialFactory(committee_id=committee_id)
other_report = factories.ReportsPresidentialFactory()
results = self._results(api.url_for(ReportsView, committee_id=committee_id))
committee_ids = [each['committee_id'] for each in results]
self.assertIn(committee_report.committee_id, committee_ids)
self.assertNotIn(other_report.committee_id, committee_ids)
self._check_committee_ids(results, [committee_report], [other_report])

def test_reports_by_committee_type(self):
presidential_report = factories.ReportsPresidentialFactory()
house_report = factories.ReportsHouseSenateFactory()
results = self._results(api.url_for(ReportsView, committee_type='presidential'))
committee_ids = [each['committee_id'] for each in results]
self.assertIn(presidential_report.committee_id, committee_ids)
self.assertNotIn(house_report.committee_id, committee_ids)
self._check_committee_ids(results, [presidential_report], [house_report])

def test_reports_by_committee_type_and_cycle(self):
presidential_report_2012 = factories.ReportsPresidentialFactory(cycle=2012)
presidential_report_2016 = factories.ReportsPresidentialFactory(cycle=2016)
house_report_2016 = factories.ReportsHouseSenateFactory(cycle=2016)
results = self._results(api.url_for(ReportsView, committee_type='presidential', year=2016))
committee_ids = [each['committee_id'] for each in results]
self.assertIn(presidential_report_2016.committee_id, committee_ids)
self.assertNotIn(presidential_report_2012.committee_id, committee_ids)
self.assertNotIn(house_report_2016.committee_id, committee_ids)
results = self._results(
api.url_for(
ReportsView,
committee_type='presidential',
cycle=2016,
)
)
self._check_committee_ids(
results,
[presidential_report_2016],
[presidential_report_2012, house_report_2016],
)
# Test repeated cycle parameter
results = self._results(
api.url_for(
ReportsView,
committee_type='presidential',
cycle=[2016, 2018],
)
)
self._check_committee_ids(
results,
[presidential_report_2016],
[presidential_report_2012, house_report_2016],
)

def test_reports_by_committee_type_and_year(self):
presidential_report_2012 = factories.ReportsPresidentialFactory(report_year=2012)
presidential_report_2016 = factories.ReportsPresidentialFactory(report_year=2016)
house_report_2016 = factories.ReportsHouseSenateFactory(report_year=2016)
results = self._results(
api.url_for(
ReportsView,
committee_type='presidential',
year=2016,
)
)
self._check_committee_ids(
results,
[presidential_report_2016],
[presidential_report_2012, house_report_2016],
)
# Test repeated cycle parameter
results = self._results(
api.url_for(
ReportsView,
committee_type='presidential',
year=[2016, 2018],
)
)
self._check_committee_ids(
results,
[presidential_report_2016],
[presidential_report_2012, house_report_2016],
)

0 comments on commit 9d3ad81

Please sign in to comment.