Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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
- Host: GitHub
- URL: https://github.com/jrycw/gt-fastapi
- Owner: jrycw
- License: mit
- Created: 2024-08-16T11:09:04.000Z (5 months ago)
- Default Branch: master
- Last Pushed: 2024-09-10T13:28:05.000Z (4 months ago)
- Last Synced: 2024-09-10T14:33:47.294Z (4 months ago)
- Topics: fastapi, pandas, polars, python, tables
- Language: Python
- Homepage:
- Size: 19.5 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
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, wrapsimport 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 szaapp = 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
)
```