Server-Side Scripting/Internet Data/Python (FastAPI)
routers/lesson8.py
edit# This program reads JSON data from Wikidata with countries
# and Celsius temperatures. It displays the data in Celsius
# and Fahrenheit sorted in decending order by temperature.
#
# References:
# https://www.mathsisfun.com/temperature-conversion.html
# https://en.wikibooks.org/wiki/Python_Programming
# https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
import json
import urllib.parse
import urllib.request
router = APIRouter(prefix="/lesson8")
templates = Jinja2Templates(directory="templates")
URL = "https://query.wikidata.org/sparql"
QUERY = """
SELECT DISTINCT ?Country ?MaximumTemperature WHERE {
?countryItem wdt:P31 wd:Q6256;
p:P6591 ?maximumTemperatureRecord.
?maximumTemperatureRecord psv:P6591 ?maximumTemperatureValue.
?maximumTemperatureValue wikibase:quantityAmount ?maximumTemperatureQuantity;
wikibase:quantityUnit ?temperatureUnit.
{
?countryItem rdfs:label ?Country.
FILTER((LANG(?Country)) = "en")
}
{
?temperatureUnit wdt:P5061 ?unitSymbol.
FILTER((LANG(?unitSymbol)) = "en")
FILTER(CONTAINS(?unitSymbol, "C"))
}
BIND(CONCAT(STR(?maximumTemperatureQuantity), " ", ?unitSymbol) AS ?MaximumTemperature)
}
ORDER BY (?Country)
"""
@router.get("/", response_class=HTMLResponse)
async def get_lesson8(request: Request):
try:
result = await get_data(URL, QUERY)
except Exception as exception:
result = exception
return templates.TemplateResponse(
"lesson8.html",
{
"request": request,
"table": result
}
)
async def get_data(url, query):
try:
data = get_raw_data(url, query)
records = get_records(data)
records.sort(key=lambda x:x["celsius"], reverse=True)
result = format_table(records)
return result
except Exception as exception:
return str(exception)
def get_raw_data(url, query):
url += "?query=" + urllib.parse.quote(query)
url += "&format=json"
data = urllib.request.urlopen(url).read().decode()
data = json.loads(data)
return data
def get_records(data):
records = []
for dictionary in data["results"]["bindings"]:
record = get_record(dictionary)
records.append(record)
records.sort(key=lambda x:x["celsius"], reverse=True)
return records
def get_record(dictionary):
country = dictionary["Country"]["value"]
celsius = dictionary["MaximumTemperature"]["value"]
index = celsius.find(" °C")
if index < 0:
raise ValueError("Invalid data format")
try:
celsius = float(celsius[0:index])
fahrenheit = celsius * 9 / 5 + 32
except:
raise ValueError("Invalid temperature data")
record = {}
record["country"] = country
record["celsius"] = celsius
record["fahrenheit"] = fahrenheit
return record
def format_table(records):
result = "<table><tr><th>Country</th>"
result += "<th>Celsius</th>"
result += "<th>Fahrenheit</th></tr>"
for record in records:
result += f"<tr><td>{record['country']}</td>"
result += f"<td>{record['celsius']:.1f}° C</td>"
result += f"<td>{record['fahrenheit']:.1f}° F</td></tr>"
result += "</table>"
return result
templates/lesson8.html
edit<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Lesson 8</title>
<link rel="stylesheet" href="{{url_for('static', path='/styles.css')}}">
<style>
p {
min-height: 1em;
}
</style>
</head>
<body>
<h1>Temperature Conversion</h1>
<h2>Wikidata</h2>
{{table|safe}}
</body>
</html>
Try It
editSee Server-Side Scripting/Routes and Templates/Python (FastAPI) to create a test environment.