Server-Side Scripting/Internet Data/Python (FastAPI)


# 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:

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 = ""
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):
        result = await get_data(URL, QUERY)
    except Exception as exception:
        result = exception

    return templates.TemplateResponse(
            "request": request,
            "table": result

async def get_data(url, query):
        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.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")

        celsius = float(celsius[0:index])
        fahrenheit = celsius * 9 / 5 + 32
        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


<!DOCTYPE html>
<html lang="en">

    <meta charset="UTF-8">
    <title>Lesson 8</title>
    <link rel="stylesheet" href="{{url_for('static', path='/styles.css')}}">
        p {
            min-height: 1em;

    <h1>Temperature Conversion</h1>


Try It


See Server-Side Scripting/Routes and Templates/Python (FastAPI) to create a test environment.

See Also