3
votes
Python Loops for JSON
How the heck do these work? I've cobbled together the script below for my bot (using Limnoria) to return the F1 standings in a line. Right now it returns the first value perfectly, but I can't figure out the loop to get the other drivers at all.
The script
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.callbacks as callbacks
import supybot.ircmsgs as ircmsgs
import requests
import os
import collections
import json
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization("F1")
except ImportError:
_ = lambda x: x
class F1(callbacks.Plugin):
"""Uses API to retrieve information"""
threaded = True
def f1(self, irc, msg, args):
"""
F1 Standings
"""
channel = msg.args[0]
data = requests.get("https://ergast.com/api/f1/2022/driverStandings.json")
data = json.loads(data.content)["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]
name = data["Driver"]["code"]
position = data["positionText"].zfill(2)
points = data["points"]
output = ", ".join(['\x0306\x02' + name + '\x0303' + " [" + position + ", "+ points + "]"])
irc.reply(output)
result = wrap(f1)
Class = F1
The output should be
VER [1, 125], LEC [2, 116], PER [3, 110], RUS [4, 84], SAI [5, 83], HAM [6, 50], NOR [7, 48], BOT [8, 40], OCO [9, 30], MAG [10, 15], RIC [11, 11], TSU [12, 11], ALO [13, 10], GAS [14, 6], VET [15, 5], ALB [16, 3], STR [17, 2], ZHO [18, 1], MSC [19, 0], HUL [20, 0], LAT [21, 0]
...but it only returns VER [1, 125]
I'm in that state where I can read the stuff, but when I put it together, it doesn't always work.
Final script
# this accepts @champ or @constructor with an optional year
# and also @gp with an optional race number for the current season
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.callbacks as callbacks
import supybot.ircmsgs as ircmsgs
import requests
import os
import collections
import json
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization("F1")
except ImportError:
_ = lambda x: x
class F1(callbacks.Plugin):
"""Uses API to retrieve information"""
threaded = True
def champ(self, irc, msg, args, year):
"""<year>
Call standings by year
F1 Standings
"""
data = requests.get("https://ergast.com/api/f1/current/driverStandings.json")
if year:
data = requests.get(
"https://ergast.com/api/f1/%s/driverStandings.json" % (year)
)
driver_standings = json.loads(data.content)["MRData"]["StandingsTable"][
"StandingsLists"
][0]["DriverStandings"]
string_segments = []
for driver in driver_standings:
name = driver["Driver"]["code"]
position = driver["positionText"]
points = driver["points"]
string_segments.append(f"\x035{name}\x0F {points}")
irc.reply(", ".join(string_segments))
champ = wrap(champ, [optional("int")])
def gp(self, irc, msg, args, race):
"""<year>
Call standings by year
F1 Standings
"""
data = requests.get("https://ergast.com/api/f1/current/last/results.json")
if race:
data = requests.get(
"https://ergast.com/api/f1/current/%s/results.json" % (race)
)
driver_result = json.loads(data.content)["MRData"]["RaceTable"]["Races"][0][
"Results"
]
string_segments = []
for driver in driver_result:
name = driver["Driver"]["code"]
position = driver["positionText"]
points = driver["points"]
string_segments.append(f"{position} \x035{name}\x0F {points}")
irc.reply(", ".join(string_segments))
gp = wrap(gp, [optional("int")])
def constructor(self, irc, msg, args, year):
"""<year>
Call standings by year
F1 Standings
"""
data = requests.get(
"https://ergast.com/api/f1/current/constructorStandings.json"
)
if year:
data = requests.get(
"https://ergast.com/api/f1/current/constructorStandings.json" % (year)
)
driver_result = json.loads(data.content)["MRData"]["StandingsTable"][
"StandingsLists"
][0]["ConstructorStandings"]
string_segments = []
for driver in driver_result:
name = driver["Constructor"]["name"]
position = driver["positionText"]
points = driver["points"]
string_segments.append(f"{position} \x035{name}\x0F {points}")
irc.reply(", ".join(string_segments))
constructor = wrap(constructor, [optional("int")])
Class = F1
So I think the problem is on the line
You only grab a single driver at the end when you wrote
[0]
.Here is a version that loops over the standings.
Output:
Not sure what you are doing with the
\x0306
stuff, but I left it in. Output without that:also fun tip, the requests library will handle the json parsing for you when the HTTP response's content type is
application/json
, like this:lol
indeed
holy shit! that works like a charm! The
\x0306
etc are mirc color codes. Here's the output, which needs some tweaking.Thanks so much for this! The loop makes more sense now. Thanks so much for this!
I think the last
[0]
in thedata = json.loads(data.content)["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]
line is too much.You're selecting the first element of that array instead of looping over the entire array.
The following worked for me:
The JSON is a bit hairy -- it gets a lot easier to analyze if you pretty-print it using the
jq
utility:jq . example.json
(the period before the filename tells it to pretty-print).thanks so much for this. I'm definitely going to look into jq.