Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jrycw/gt-fastapi

Great Tables running in FastAPI
https://github.com/jrycw/gt-fastapi

fastapi pandas polars python tables

Last synced: about 1 month ago
JSON representation

Great Tables running in FastAPI

Awesome Lists containing this project

README

        

# gt-fastapi

### Introduction

This guide will walk you through setting up a FastAPI application that renders a table using the `GT` library.

### Steps

1. **Create a FastAPI App Instance**

Start by creating an instance of the FastAPI app:

```python
app = FastAPI()
```

2. **Create the `index` Endpoint**

Define the `index` endpoint, which will generate an HTML table using `GT.as_raw_html()` and return it via `templates.TemplateResponse` when users visit the `/` route:

```python
@cache
def get_sza():
return pl.from_pandas(sza)

@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
sza_pivot = (
get_sza()
.filter((pl.col("latitude") == "20") & (pl.col("tst") <= "1200"))
.select(pl.col("*").exclude("latitude"))
.drop_nulls()
.pivot(values="sza", index="month", on="tst", sort_columns=True)
)

sza_gt = (
GT(sza_pivot, rowname_col="month")
.data_color(
domain=[90, 0],
palette=["rebeccapurple", "white", "orange"],
na_color="white",
)
.tab_header(
title="Solar Zenith Angles from 05:30 to 12:00",
subtitle=html("Average monthly values at latitude of 20°N."),
)
.sub_missing(missing_text="")
)

context = {"sza_gt": sza_gt.as_raw_html()}

return templates.TemplateResponse(
request=request, name="index.html", context=context
)
```

3. **Set Up the Template**

Create a `templates` directory and an `index.html` file within it. This file will render the HTML table generated by the `index` endpoint. Be sure to use the `safe` template tag to prevent Jinja from escaping the HTML:

```html






FastAPI-GT Website



Great Tables shown in FastAPI




{{ sza_gt | safe }}



```

4. **Run the Uvicorn Server**

Finally, start the Uvicorn server and open your browser to view the rendered table:

```bash
uvicorn main:app --reload
```

You should now see the table displayed in your browser at http://127.0.0.1:8000.

![table](https://raw.githubusercontent.com/jrycw/gt-fastapi/refs/heads/master/gt-fastapi.png)

### Alternative steps
Alternatively, you could use the decorator approach to avoid calling `GT.as_raw_html()` for each `GT` instance. However, I'm unsure if this method is actually easier for developers.

**Please note that the `gt2fastapi` decorator is for demonstration purposes only and is not fully implemented. You will also need to handle additional information, such as [status codes, headers, media types, and background tasks](https://fastapi.tiangolo.com/reference/templating/?h=templatere#fastapi.templating.Jinja2Templates.TemplateResponse)**.

```python
import inspect
from functools import cache, partial, wraps

import polars as pl
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from great_tables import GT, html
from great_tables.data import sza

app = FastAPI()

templates = Jinja2Templates(directory="templates")

@cache
def get_sza():
return pl.from_pandas(sza)

def gt2fastapi(func=None):
"""
https://pybit.es/articles/decorator-optional-argument/
"""

def _get_template_response(resp):
context = resp.context
request = context.pop("request")
name = resp.template.name
new_context = {}
for key, value in context.items():
if isinstance(value, GT):
value = value.as_raw_html()
new_context[key] = value
return templates.TemplateResponse(
request=request, name=name, context=new_context
)

if func is None:
return partial(gt2fastapi)

@wraps(func)
async def async_wrapper(*args, **kwargs):
resp = await func(*args, **kwargs)
return _get_template_response(resp)

@wraps(func)
def wrapper(*args, **kwargs):
resp = func(*args, **kwargs)
return _get_template_response(resp)

return async_wrapper if inspect.iscoroutinefunction(func) else wrapper

@app.get("/", response_class=HTMLResponse)
@gt2fastapi
def index(request: Request):
sza_pivot = (
get_sza()
.filter((pl.col("latitude") == "20") & (pl.col("tst") <= "1200"))
.select(pl.col("*").exclude("latitude"))
.drop_nulls()
.pivot(values="sza", index="month", on="tst", sort_columns=True)
)

sza_gt = (
GT(sza_pivot, rowname_col="month")
.data_color(
domain=[90, 0],
palette=["rebeccapurple", "white", "orange"],
na_color="white",
)
.tab_header(
title="Solar Zenith Angles from 05:30 to 12:00",
subtitle=html("Average monthly values at latitude of 20°N."),
)
.sub_missing(missing_text="")
)

context = {"sza_gt": sza_gt}

return templates.TemplateResponse(
request=request, name="index.html", context=context
)

@app.get("/async", response_class=HTMLResponse)
@gt2fastapi
async def async_index(request: Request):
sza_pivot = (
get_sza()
.filter((pl.col("latitude") == "20") & (pl.col("tst") <= "1200"))
.select(pl.col("*").exclude("latitude"))
.drop_nulls()
.pivot(values="sza", index="month", on="tst", sort_columns=True)
)

sza_gt = (
GT(sza_pivot, rowname_col="month")
.data_color(
domain=[90, 0],
palette=["orange", "white", "rebeccapurple"],
na_color="white",
)
.tab_header(
title="Solar Zenith Angles from 05:30 to 12:00",
subtitle=html("Average monthly values at latitude of 20°N."),
)
.sub_missing(missing_text="")
)

context = {"sza_gt": sza_gt}

return templates.TemplateResponse(
request=request, name="index.html", context=context
)
```