Skip to content

Commit e8c62c0

Browse files
authored
Merge pull request #201 from pittcsc/mypy-sports
Refactor `sports.py` to use `NamedTuple`, fix `mypy` errors
2 parents cbe748b + 32c88e9 commit e8c62c0

File tree

2 files changed

+54
-48
lines changed

2 files changed

+54
-48
lines changed

pittapi/sports.py

+42-30
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,39 @@
1717
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1818
"""
1919

20+
from __future__ import annotations
21+
2022
import requests
2123

24+
from typing import Any, NamedTuple
25+
26+
JSON = dict[str, Any]
27+
2228
FOOTBALL_URL = "http://site.api.espn.com/apis/site/v2/sports/football/college-football/teams/pitt"
2329
MENS_BASKETBALL_URL = "http://site.api.espn.com/apis/site/v2/sports/basketball/mens-college-basketball/teams/pittsburgh"
2430

2531

32+
class GameInfo(NamedTuple):
33+
timestamp: str | None = None
34+
opponent: dict[str, str] | None = None
35+
home_away: str | None = None
36+
location: dict[str, str] | None = None
37+
status: str | None = None
38+
39+
2640
def get_mens_basketball_record() -> str:
2741
"""returns the current record of the men's basketball team"""
2842
basketball_data = _get_mens_basketball_data()
2943

3044
try:
31-
record_summary = basketball_data["team"]["record"]["items"][0]["summary"]
32-
45+
record_summary: str = basketball_data["team"]["record"]["items"][0]["summary"]
3346
except KeyError:
3447
record_summary = "There's no record right now."
3548

3649
return record_summary
3750

3851

39-
def get_next_mens_basketball_game() -> dict:
52+
def get_next_mens_basketball_game() -> GameInfo:
4053
"""returns a dict containing details of the next scheduled men's basketball game."""
4154
basketball_data = _get_mens_basketball_data()
4255
next_game = None
@@ -55,30 +68,29 @@ def get_next_mens_basketball_game() -> dict:
5568
else:
5669
opponent = next_game["competitions"][0]["competitors"][1]
5770
homeaway = next_game["competitions"][0]["competitors"][1]["homeAway"]
58-
return {
59-
"timestamp": next_game["date"],
60-
"opponent": {
71+
return GameInfo(
72+
timestamp=next_game["date"],
73+
opponent={
6174
"id": opponent["team"]["id"],
6275
"school": opponent["team"]["nickname"],
6376
"name": opponent["team"]["displayName"],
6477
},
65-
"home_away": homeaway,
66-
"location": {
78+
home_away=homeaway,
79+
location={
6780
"full_name": next_game["competitions"][0]["venue"]["fullName"],
6881
"address": next_game["competitions"][0]["venue"]["address"],
6982
},
70-
"status": status,
71-
}
83+
status=status,
84+
)
7285
except IndexError:
7386
# IndexError occurs when a next game on the schedule is not present
74-
return {"status": "NO_GAME_SCHEDULED"}
87+
return GameInfo(status="NO_GAME_SCHEDULED")
7588

7689

7790
def get_mens_basketball_standings() -> str:
7891
"""returns a string describing the placement of the men's basketball team. eg: '14th in ACC'"""
7992
basketball_data = _get_mens_basketball_data()
80-
81-
return_value = basketball_data["team"]["standingSummary"]
93+
return_value: str = basketball_data["team"]["standingSummary"]
8294
return return_value
8395

8496

@@ -87,15 +99,14 @@ def get_football_record() -> str:
8799
football_data = _get_football_data()
88100

89101
try:
90-
record_summary = football_data["team"]["record"]["items"][0]["summary"]
91-
102+
record_summary: str = football_data["team"]["record"]["items"][0]["summary"]
92103
except KeyError:
93104
record_summary = "There's no record right now."
94105

95106
return record_summary
96107

97108

98-
def get_next_football_game() -> dict:
109+
def get_next_football_game() -> GameInfo:
99110
football_data = _get_football_data()
100111
next_game = None
101112
try:
@@ -113,36 +124,37 @@ def get_next_football_game() -> dict:
113124
else:
114125
opponent = next_game["competitions"][0]["competitors"][0]
115126
homeaway = next_game["competitions"][0]["competitors"][1]["homeAway"]
116-
return {
117-
"timestamp": next_game["date"],
118-
"opponent": {
127+
return GameInfo(
128+
timestamp=next_game["date"],
129+
opponent={
119130
"id": opponent["team"]["id"],
120131
"school": opponent["team"]["nickname"],
121132
"name": opponent["team"]["displayName"],
122133
},
123-
"home_away": homeaway,
124-
"location": {
134+
home_away=homeaway,
135+
location={
125136
"full_name": next_game["competitions"][0]["venue"]["fullName"],
126137
"address": next_game["competitions"][0]["venue"]["address"],
127138
},
128-
"status": status,
129-
}
139+
status=status,
140+
)
130141
except IndexError:
131142
# IndexError occurs when a next game on the schedule is not present
132-
return {"status": "NO_GAME_SCHEDULED"}
143+
return GameInfo(status="NO_GAME_SCHEDULED")
133144

134145

135146
def get_football_standings() -> str:
136147
"""returns a string describing the placement of the football team. eg: '14th in ACC'"""
137148
football_data = _get_football_data()
138-
139-
return_value = football_data["team"]["standingSummary"]
149+
return_value: str = football_data["team"]["standingSummary"]
140150
return return_value
141151

142152

143-
def _get_mens_basketball_data() -> dict:
144-
return requests.get(MENS_BASKETBALL_URL).json()
153+
def _get_mens_basketball_data() -> JSON:
154+
json_data: JSON = requests.get(MENS_BASKETBALL_URL).json()
155+
return json_data
145156

146157

147-
def _get_football_data() -> dict:
148-
return requests.get(FOOTBALL_URL).json()
158+
def _get_football_data() -> JSON:
159+
json_data: JSON = requests.get(FOOTBALL_URL).json()
160+
return json_data

tests/sports_test.py

+12-18
Original file line numberDiff line numberDiff line change
@@ -170,36 +170,30 @@ def test_get_football_standings(self):
170170

171171
def test_get_next_mens_basketball_game(self):
172172
next_game_details = sports.get_next_mens_basketball_game()
173-
self.assertIn("timestamp", next_game_details)
174-
self.assertIn("opponent", next_game_details)
175-
self.assertIn("home_away", next_game_details)
176-
self.assertIn("location", next_game_details)
177-
self.assertIn("status", next_game_details)
178-
self.assertNotEqual("NO_GAME_SCHEDULED", next_game_details["status"])
173+
self.assertNotEqual("NO_GAME_SCHEDULED", next_game_details.status)
179174

180175
def test_get_next_football_game(self):
181176
next_game_details = sports.get_next_football_game()
182-
self.assertIn("timestamp", next_game_details)
183-
self.assertIn("opponent", next_game_details)
184-
self.assertIn("home_away", next_game_details)
185-
self.assertIn("location", next_game_details)
186-
self.assertIn("status", next_game_details)
187-
self.assertNotEqual("NO_GAME_SCHEDULED", next_game_details["status"])
177+
self.assertNotEqual("NO_GAME_SCHEDULED", next_game_details.status)
188178

189179
def test_get_next_mens_basketball_game_offseason(self):
190180
offseason_data = {"team": {"nextEvent": []}}
191181
sports._get_mens_basketball_data = MagicMock(return_value=offseason_data)
192182

193183
next_game_details = sports.get_next_mens_basketball_game()
194-
self.assertEqual(1, len(next_game_details))
195-
self.assertIn("status", next_game_details)
196-
self.assertEqual("NO_GAME_SCHEDULED", next_game_details["status"])
184+
self.assertIsNone(next_game_details.timestamp)
185+
self.assertIsNone(next_game_details.opponent)
186+
self.assertIsNone(next_game_details.home_away)
187+
self.assertIsNone(next_game_details.location)
188+
self.assertEqual("NO_GAME_SCHEDULED", next_game_details.status)
197189

198190
def test_get_next_football_game_offseason(self):
199191
offseason_data = {"team": {"nextEvent": []}}
200192
sports._get_football_data = MagicMock(return_value=offseason_data)
201193

202194
next_game_details = sports.get_next_football_game()
203-
self.assertEqual(1, len(next_game_details))
204-
self.assertIn("status", next_game_details)
205-
self.assertEqual("NO_GAME_SCHEDULED", next_game_details["status"])
195+
self.assertIsNone(next_game_details.timestamp)
196+
self.assertIsNone(next_game_details.opponent)
197+
self.assertIsNone(next_game_details.home_away)
198+
self.assertIsNone(next_game_details.location)
199+
self.assertEqual("NO_GAME_SCHEDULED", next_game_details.status)

0 commit comments

Comments
 (0)