Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions frameworks/turboapi/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# TurboAPI — Python 3.14 free-threaded + Zig 0.15 native backend
FROM python:3.14-bookworm AS builder

# Install Zig 0.15.2
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "arm64" ]; then ZIG_ARCH=aarch64; else ZIG_ARCH=x86_64; fi \
&& curl -fSL "https://ziglang.org/download/0.15.2/zig-${ZIG_ARCH}-linux-0.15.2.tar.xz" \
| tar -xJ -C /opt \
&& ln -s /opt/zig-${ZIG_ARCH}-linux-0.15.2/zig /usr/local/bin/zig

# Build Python 3.14 free-threaded from source
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
libsqlite3-dev libncurses5-dev libffi-dev liblzma-dev \
&& PYVER=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')") \
&& curl -fSL "https://www.python.org/ftp/python/${PYVER}/Python-${PYVER}.tgz" | tar xz -C /tmp \
&& cd /tmp/Python-${PYVER} \
&& ./configure --prefix=/opt/python3.14t --disable-gil --enable-shared --with-ensurepip=install \
LDFLAGS="-Wl,-rpath,/opt/python3.14t/lib" 2>&1 | tail -5 \
&& make -j$(nproc) 2>&1 | tail -3 \
&& make install 2>&1 | tail -3 \
&& /opt/python3.14t/bin/python3 -c "import sys; assert not sys._is_gil_enabled(); print('Free-threaded OK')" \
&& rm -rf /tmp/Python-*

ENV PATH="/opt/python3.14t/bin:$PATH"

WORKDIR /app

# download TurboAPI sources
#RUN git clone --depth 1 --branch v1.0.27 https://github.com/justrach/turboAPI.git .
RUN git clone https://github.com/justrach/turboAPI.git . && git checkout 1c80c67fbe002892db661247c770ad0fbd447904

# patch dhi
RUN sed -i 's|\(\.url = "\)[^"]*github\.com/justrach/dhi/[^"]*"|\1git+https://github.com/justrach/dhi?ref=main#44a3b88f37ffb095c05c668e0b2561f75d6aed1e"|' /app/zig/build.zig.zon

# Build the Zig native backend (dhi fetched automatically via build.zig.zon)
RUN python3 zig/build_turbonet.py --install --release


# --- Runtime stage ---

FROM debian:bookworm-slim

# Copy free-threaded Python + turboapi
COPY --from=builder /opt/python3.14t /opt/python3.14t
ENV PATH="/opt/python3.14t/bin:$PATH"

# Runtime deps for Python
RUN apt-get update && apt-get install -y --no-install-recommends \
libssl3 zlib1g libbz2-1.0 libreadline8 libsqlite3-0 \
libncurses6 libffi8 liblzma5 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY --from=builder /app /app
COPY app.py /app/app.py

# Install turboapi + deps
RUN pip3 install --no-cache-dir -e .

EXPOSE 8000

CMD ["python3", "app.py"]
99 changes: 99 additions & 0 deletions frameworks/turboapi/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import os
import sys
import multiprocessing
import json

os.environ["TURBO_DISABLE_RATE_LIMITING"] = "1"
os.environ["TURBO_DISABLE_CACHE"] = "1"

# -- Dataset and constants --------------------------------------------------------

CPU_COUNT = int(multiprocessing.cpu_count())
WRK_COUNT = min(len(os.sched_getaffinity(0)), 128)
WRK_COUNT = max(WRK_COUNT, 4)

DATASET_LARGE_PATH = "/data/dataset-large.json"
DATASET_PATH = os.environ.get("DATASET_PATH", "/data/dataset.json")
DATASET_ITEMS = None
try:
with open(DATASET_PATH) as file:
DATASET_ITEMS = json.load(file)
except Exception:
pass


# -- APP -----------------------------------------------------------------------

from turboapi.request_handler import RequestBodyParser

original_parse_json_body = RequestBodyParser.parse_json_body

def fixed_parse_json_body(body, handler_signature):
if not body:
return { }
if body.startswith(b'{') or body.startswith(b'['):
return original_parse_json_body(body, handler_signature)
return { "_BODY_": body.decode(errors="replace") }

RequestBodyParser.parse_json_body = staticmethod(fixed_parse_json_body)

from turboapi import TurboAPI, Request, Path, Query, File, UploadFile, HTTPException
from turboapi.responses import PlainTextResponse, JSONResponse
from turboapi.middleware import GZipMiddleware
from turboapi.staticfiles import StaticFiles

app = TurboAPI()

app.add_middleware(GZipMiddleware, minimum_size=1, compresslevel=5)


# -- Routes ------------------------------------------------------------------

@app.get("/pipeline")
def pipeline():
return PlainTextResponse(b"ok")


@app.get("/baseline11")
def baseline11(a, b):
return PlainTextResponse( str( int(a) + int(b) ) )


@app.post("/baseline11")
def baseline11body(a, b, _BODY_):
return PlainTextResponse( str( int(a) + int(b) + int(_BODY_) ) )


def json_common(count: int, m_val: float):
global DATASET_ITEMS
if not DATASET_ITEMS:
return PlainTextResponse("No dataset", 500)
try:
items = [ ]
for idx, dsitem in enumerate(DATASET_ITEMS):
if idx >= count:
break
item = dict(dsitem)
item["total"] = dsitem["price"] * dsitem["quantity"] * m_val
items.append(item)
return { "items": items, "count": len(items) }
except Exception:
return { "items": [ ], "count": 0 }


@app.get("/json/{count}")
def json_endpoint(count, m):
count = int(count)
m = float(m)
return json_common(count, m)


@app.get("/json-comp/{count}")
def json_comp_endpoint(count, m):
count = int(count)
m = float(m)
return json_common(count, m)


if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
16 changes: 16 additions & 0 deletions frameworks/turboapi/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"display_name": "turboapi",
"language": "Python",
"type": "tuned",
"engine": "TurboNet-Zig",
"description": "FastAPI-compatible Python framework (Zig HTTP core)",
"repo": "https://github.com/justrach/turboAPI",
"enabled": true,
"tests": [
"baseline",
"pipelined",
"json",
"json-comp"
],
"maintainers": []
}
Loading