Skip to content

Commit bcc38a9

Browse files
authored
Use legislative session as fallback value for Fiscal Year in search (#1304)
* Use legislative_session.start_date as fallback for Fiscal Year derivation - Retain previous logic for bills with more than one agenda or action item. - Add fallback for items like Board Correspondence, which have 1 or 0 actions/agendas, but do have an attached legislative session. - Use manual splitting to get year from legislative session dates , which we know are generated strings in the format "%Y-%m-%d" from the scraper `(Lametro.legislative_sessions()` in `lametro/__init__.py`). * Testing changes - Add start and end date to legislative session fixture - Add test for legislative session fallback - Factor out a few helper functions
1 parent 83ba16b commit bcc38a9

3 files changed

Lines changed: 71 additions & 54 deletions

File tree

lametro/search_indexes.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,35 @@ def prepare_attachment_text(self, obj):
6565
)
6666

6767
def prepare_legislative_session(self, obj):
68+
"""
69+
Returns a fiscal year string for a given bill based on latest
70+
action or agenda date.
71+
72+
If a bill doesn't have more than one of either, then use the
73+
legislative session as fallback value.
74+
"""
6875
aa = sorted(obj.actions_and_agendas, key=lambda i: i["date"], reverse=True)
6976
agendas = [a for a in aa if a["description"] == "SCHEDULED"]
70-
if len(aa) > 1:
71-
if agendas:
72-
action_date = agendas[0]["date"]
73-
else:
74-
action_date = aa[0]["date"]
77+
start_year = None
78+
end_year = None
7579

80+
if len(aa) > 1:
81+
action_date = agendas[0]["date"] if agendas else aa[0]["date"]
7682
if action_date.month <= 6:
7783
start_year = action_date.year - 1
7884
end_year = action_date.year
7985
else:
8086
start_year = action_date.year
8187
end_year = action_date.year + 1
88+
elif session := obj.legislative_session:
89+
start_year = session.start_date.split("-")[0]
90+
end_year = session.end_date.split("-")[0]
91+
else:
92+
return None
8293

83-
session = "7/1/{start_year} to 6/30/{end_year}".format(
84-
start_year=start_year, end_year=end_year
85-
)
86-
return session
87-
return None
94+
return "7/1/{start_year} to 6/30/{end_year}".format(
95+
start_year=start_year, end_year=end_year
96+
)
8897

8998
def prepare_topics(self, obj):
9099
return self._topics_from_classification(obj, "topics_exact")

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ def legislative_session(db, jurisdiction):
113113
"identifier": "2017",
114114
"jurisdiction_id": "ocd-jurisdiction/country:us/state:ca/county:los_angeles/transit_authority",
115115
"name": "2017 Legislative Session",
116+
"start_date": "2017-07-01",
117+
"end_date": "2018-06-30",
116118
}
117119

118120
session = LegislativeSession.objects.create(**session_info)

tests/test_solr_prep.py

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
from lametro.search_indexes import LAMetroBillIndex
77

88

9+
# Helper function
10+
def patch_aa(mocker, return_value):
11+
mocker.patch(
12+
"lametro.models.LAMetroBill.actions_and_agendas",
13+
new_callable=mocker.PropertyMock,
14+
return_value=return_value,
15+
)
16+
17+
918
@pytest.mark.parametrize("month", [6, 7])
1019
def test_legislative_session(bill, metro_organization, event, mocker, month):
1120
"""
@@ -16,11 +25,12 @@ def test_legislative_session(bill, metro_organization, event, mocker, month):
1625
which returns a dict of prepped data.
1726
https://github.com/django-haystack/django-haystack/blob/4910ccb01c31d12bf22dcb000894eece6c26f74b/haystack/indexes.py#L198
1827
"""
28+
# Set up
29+
now = datetime.now()
1930
org = metro_organization.build()
2031
event = event.build()
2132
bill = bill.build()
22-
23-
now = datetime.now()
33+
index = LAMetroBillIndex()
2434

2535
# Create test actions and agendas
2636
recent_action = {
@@ -48,66 +58,62 @@ def test_legislative_session(bill, metro_organization, event, mocker, month):
4858
"organization": org,
4959
}
5060

61+
def date_to_fy_string(date):
62+
"""
63+
Return the correct fiscal year for a given date, June (6) being the last month of the year.
64+
"""
65+
start_year = date.year - 1 if date.month <= 6 else date.year
66+
end_year = date.year if date.month <= 6 else date.year + 1
67+
return "7/1/{0} to 6/30/{1}".format(start_year, end_year)
68+
5169
# Test indexed value when there are both actions and agendas
52-
mock_actions_and_agendas = mocker.PropertyMock(
53-
return_value=[recent_action, older_action, recent_agenda, older_agenda]
54-
)
5570

56-
mocker.patch(
57-
"lametro.models.LAMetroBill.actions_and_agendas",
58-
new_callable=mock_actions_and_agendas,
59-
)
71+
patch_aa(mocker, [recent_action, older_action, recent_agenda, older_agenda])
72+
indexed_data = index.prepare(bill)
73+
expected_value = date_to_fy_string(recent_agenda["date"])
6074

61-
index = LAMetroBillIndex()
62-
expected_fmt = "7/1/{0} to 6/30/{1}"
75+
assert indexed_data["legislative_session"] == expected_value
6376

64-
indexed_data = index.prepare(bill)
77+
# Test indexed value when there are just actions
6578

66-
if month <= 6:
67-
expected_value = expected_fmt.format(
68-
recent_agenda["date"].year - 1, recent_agenda["date"].year
69-
)
70-
else:
71-
expected_value = expected_fmt.format(
72-
recent_agenda["date"].year, recent_agenda["date"].year + 1
73-
)
79+
patch_aa(mocker, [recent_action, older_action])
80+
indexed_data = index.prepare(bill)
81+
expected_value = date_to_fy_string(recent_action["date"])
7482

7583
assert indexed_data["legislative_session"] == expected_value
7684

77-
# Test indexed value when there are just actions
78-
mock_actions_and_agendas = mocker.PropertyMock(
79-
return_value=[recent_action, older_action]
80-
)
8185

82-
mocker.patch(
83-
"lametro.models.LAMetroBill.actions_and_agendas",
84-
new_callable=mock_actions_and_agendas,
85-
)
86+
def test_legislative_session_fallback(bill, metro_organization, event, mocker):
87+
bill = bill.build()
88+
event = event.build()
89+
org = metro_organization.build()
90+
session = bill.legislative_session
91+
index = LAMetroBillIndex()
92+
now = datetime.now()
8693

87-
indexed_data = index.prepare(bill)
94+
single_action = {
95+
"date": datetime(now.year, 7, 1),
96+
"description": "action descripton",
97+
"event": event,
98+
"organization": org,
99+
}
100+
101+
patch_aa(mocker, [single_action])
88102

89-
if month <= 6:
90-
expected_value = expected_fmt.format(
91-
recent_action["date"].year - 1, recent_action["date"].year
92-
)
93-
else:
94-
expected_value = expected_fmt.format(
95-
recent_action["date"].year, recent_action["date"].year + 1
96-
)
103+
indexed_data = index.prepare(bill)
104+
expected_fmt = "7/1/{0} to 6/30/{1}"
105+
expected_value = expected_fmt.format(
106+
session.start_date.split("-")[0], session.end_date.split("-")[0]
107+
)
97108

98109
assert indexed_data["legislative_session"] == expected_value
99110

100111
# Test indexed value when there are neither actions nor agendas
101-
mock_actions_and_agendas = mocker.PropertyMock(return_value=[])
102-
103-
mocker.patch(
104-
"lametro.models.LAMetroBill.actions_and_agendas",
105-
new_callable=mock_actions_and_agendas,
106-
)
107112

113+
patch_aa(mocker, [])
108114
indexed_data = index.prepare(bill)
109115

110-
assert not indexed_data["legislative_session"]
116+
assert indexed_data["legislative_session"] == expected_value
111117

112118

113119
def test_sponsorships(bill, metro_organization, event, event_related_entity, mocker):

0 commit comments

Comments
 (0)