Compare commits

..
Author SHA1 Message Date
Typosaurus 63366bb240 ticket #93 attempt 1
DevPlace CI / test (pull_request) Failing after 11s
2026-07-23 02:03:12 +00:00
Typosaurus a55d12696a ticket #93 attempt 1 2026-07-23 01:33:37 +00:00
9 changed files with 6 additions and 91 deletions
File diff suppressed because one or more lines are too long
-2
View File
@@ -38,7 +38,6 @@ def field(
example="", example="",
description="", description="",
options=None, options=None,
nullable=False,
): ):
spec = { spec = {
"name": name, "name": name,
@@ -47,7 +46,6 @@ def field(
"required": required, "required": required,
"example": example, "example": example,
"description": description, "description": description,
"nullable": nullable,
} }
if options: if options:
spec["options"] = list(options) spec["options"] = list(options)
+2 -11
View File
@@ -39,15 +39,7 @@ def _unwrap_optional(annotation):
return annotation return annotation
def _is_optional(annotation): def _value(name, annotation, stack):
if get_origin(annotation) is Union:
return type(None) in get_args(annotation)
return False
def _value(name, annotation, stack, is_nullable=False):
if is_nullable:
return None
annotation = _unwrap_optional(annotation) annotation = _unwrap_optional(annotation)
origin = get_origin(annotation) origin = get_origin(annotation)
if origin in (list, set, tuple): if origin in (list, set, tuple):
@@ -79,8 +71,7 @@ def _from_model(model, stack):
stack = stack | {model} stack = stack | {model}
example = {} example = {}
for name, info in model.model_fields.items(): for name, info in model.model_fields.items():
is_nullable = _is_optional(info.annotation) example[name] = _value(name, info.annotation, stack)
example[name] = _value(name, info.annotation, stack, is_nullable)
return example return example
-5
View File
@@ -12,7 +12,6 @@ from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.exceptions import RequestValidationError from fastapi.exceptions import RequestValidationError
from starlette.middleware.gzip import GZipMiddleware
from devplacepy.config import ( from devplacepy.config import (
STATIC_DIR, STATIC_DIR,
STATIC_VERSION, STATIC_VERSION,
@@ -610,10 +609,6 @@ async def response_timing(request: Request, call_next):
response.headers["X-Response-Time"] = f"{(time.perf_counter() - start) * 1000:.1f}ms" response.headers["X-Response-Time"] = f"{(time.perf_counter() - start) * 1000:.1f}ms"
return response return response
app.add_middleware(GZipMiddleware, minimum_size=512, compresslevel=5)
_home_cache = TTLCache(ttl=int(os.environ.get("DEVPLACE_HOME_CACHE_TTL", "60")), max_size=4) _home_cache = TTLCache(ttl=int(os.environ.get("DEVPLACE_HOME_CACHE_TTL", "60")), max_size=4)
-10
View File
@@ -218,16 +218,6 @@
font-weight: 700; font-weight: 700;
} }
.param-nullable {
font-size: 0.625rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
border: 1px dashed var(--border);
border-radius: 999px;
padding: 0.05rem 0.4rem;
}
.param-loc { .param-loc {
font-size: 0.625rem; font-size: 0.625rem;
text-transform: uppercase; text-transform: uppercase;
-1
View File
@@ -139,7 +139,6 @@ export class ApiTester {
const label = this.el("div", { class: "param-label" }, [ const label = this.el("div", { class: "param-label" }, [
this.el("span", { class: "param-name", text: param.name }), this.el("span", { class: "param-name", text: param.name }),
param.required ? this.el("span", { class: "param-required", text: "*" }) : null, param.required ? this.el("span", { class: "param-required", text: "*" }) : null,
param.nullable ? this.el("span", { class: "param-nullable", text: "nullable" }) : null,
this.el("span", { class: "param-loc param-loc-" + param.location, text: param.location }), this.el("span", { class: "param-loc param-loc-" + param.location, text: param.location }),
]); ]);
const allowed = param.type === "enum" && param.options && param.options.length const allowed = param.type === "enum" && param.options && param.options.length
@@ -11,7 +11,7 @@ How a request flows through middleware to a router, how the database layer is bu
## Middleware ## Middleware
Seven HTTP middlewares run as a stack around every request, listed outermost first. `response_timing` is the outermost, `refresh_db_snapshot` the innermost, and a `GZipMiddleware` (responses over 512 bytes) wraps the whole stack on top: Six HTTP middlewares run as a stack around every request, listed outermost first. `response_timing` is the outermost and `refresh_db_snapshot` the innermost. Compression is handled by nginx in production; the Python application does not compress responses itself.
| Middleware (outermost first) | Responsibility | | Middleware (outermost first) | Responsibility |
|------------|----------------| |------------|----------------|
+2 -1
View File
@@ -4,7 +4,8 @@ version = "1.0.0"
description = "DevPlace - The Developer Social Network" description = "DevPlace - The Developer Social Network"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [ dependencies = [
"fastapi", "fastapi>=0.110.0",
"starlette>=0.37.0",
"uvicorn[standard]", "uvicorn[standard]",
"jinja2", "jinja2",
"python-multipart", "python-multipart",
-59
View File
@@ -1,59 +0,0 @@
# retoor <retoor@molodetz.nl>
from typing import Optional
from pydantic import BaseModel
from devplacepy.docs_api._shared import field
from devplacepy.docs_examples import _is_optional, schema_example
def test_field_nullable_parameter():
f = field("bio", "query", "string", False, "", "User biography", nullable=True)
assert f["nullable"] is True
f2 = field("username", "path", "string", True, "alice", "Target username")
assert f2["nullable"] is False
def test_is_optional_optional_type():
assert _is_optional(Optional[str]) is True
assert _is_optional(Optional[int]) is True
assert _is_optional(Optional[list[str]]) is True
def test_is_optional_non_optional():
assert _is_optional(str) is False
assert _is_optional(int) is False
assert _is_optional(list[str]) is False
assert _is_optional(dict) is False
def test_schema_example_nullable_fields():
class NullableModel(BaseModel):
name: str
bio: Optional[str] = None
age: int
score: Optional[int] = None
tags: Optional[list[str]] = None
result = schema_example(NullableModel)
assert result["name"] == "string"
assert result["age"] == 0
assert result["bio"] is None
assert result["score"] is None
assert result["tags"] is None
def test_schema_example_non_nullable_fields_unaffected():
class StrictModel(BaseModel):
x: str
y: int
z: bool
result = schema_example(StrictModel)
assert result["x"] == "string"
assert result["y"] == 0
assert result["z"] is False