Skip to content

Commit

Permalink
fixtures as dev_reset
Browse files Browse the repository at this point in the history
  • Loading branch information
jrycw committed Mar 7, 2024
1 parent e3a5527 commit 9a04335
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 86 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,13 @@ jobs:
run: |
python -m pip install uv
uv venv
uv pip install -r requirements.txt -U
uv pip install -r requirements-ci.txt -U
- name: Activate virtualenv
run: |
. .venv/bin/activate
echo PATH=$PATH >> $GITHUB_ENV
- name: Set env
run: echo "secret_csrf=$(openssl rand -hex 32)" >> $GITHUB_ENV

- name: Test with pytest
run: pytest --cov=app --cov-report=html tests/

Expand Down
19 changes: 17 additions & 2 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
from .logging import CLogLevel


# TODO: Decouple the messy and decide what variables should be include in the .env
class Settings(BaseSettings):
frontend_schema: str = "http"
frontend_host: str = "localhost"
frontend_port: int = 7000
frontend_reload: bool = False
frontend_log_json_format: bool = False
frontend_log_level: CLogLevel = CLogLevel.INFO
tz: str = "UTC"

backend_schema: str = "http"
backend_host: str = "localhost"
Expand All @@ -22,9 +24,22 @@ class Settings(BaseSettings):
backend_log_json_format: bool = False
backend_log_level: CLogLevel = CLogLevel.INFO

tz: str = "UTC"

model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")


settings = Settings()


def get_backend_http_client_baseurl():
return (
f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}"
)


def get_frontend_http_client_baseurl():
return f"{settings.frontend_schema}://{settings.frontend_host}:{settings.frontend_port}"


# TODO: EdgeDB cloud
def get_db_dsn():
pass
18 changes: 8 additions & 10 deletions app/fixtures.py → app/dev_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
from edgedb.asyncio_client import AsyncIOClient
from fastapi import APIRouter, Body

from .factories import gen_event
from .factories import gen_default_dev_data
from .models import DevDataCreate
from .queries import create_event_async_edgeql as create_event_qry
from .queries import prepare_dev_data_async_edgeql as prepare_dev_data_qry
from .queries import set_default_dev_data_async_edgeql as set_default_dev_data_qry

router = APIRouter(include_in_schema=False)


@router.post(
"/fixtures",
"/reset",
status_code=HTTPStatus.OK,
response_model=list[create_event_qry.CreateEventResult],
tags=["fixtures"],
tags=["reset"],
)
async def prepare_dev_data(
async def reset_default_dev_data(
services: svcs.fastapi.DepContainer,
dev_data: Annotated[DevDataCreate, Body()] = DevDataCreate(),
):
Expand All @@ -30,8 +30,6 @@ async def prepare_dev_data(
Well, after all, this is a setup for dev.
"""
client = await services.aget(AsyncIOClient)
data = [
gen_event().model_dump(include={"name", "address", "schedule", "host_name"})
for _ in range(dev_data.n)
]
return await prepare_dev_data_qry.prepare_dev_data(client, data=json.dumps(data))
return await set_default_dev_data_qry.set_default_dev_data(
client, data=json.dumps(gen_default_dev_data(dev_data.n))
)
11 changes: 10 additions & 1 deletion app/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ class FakeEventData(BaseModel):
may be beneficial for testing purposes.
"""

name: str = Field(default_factory=lambda: faker.text(max_nb_chars=20))
name: str = Field(
default_factory=lambda: faker.text(max_nb_chars=30), max_length=50
)
address: str | None = Field(
default_factory=random.choice([faker.street_address, lambda: None])
)
Expand All @@ -34,3 +36,10 @@ class FakeEventData(BaseModel):
host_name: str = Field(default_factory=faker.name, max_length=50)

return FakeEventData()


def gen_default_dev_data(n):
return [
gen_event().model_dump(include={"name", "address", "schedule", "host_name"})
for _ in range(n)
]
32 changes: 19 additions & 13 deletions app/lifespan.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from functools import partial

import edgedb
Expand All @@ -7,7 +8,9 @@
from httpx import AsyncClient # noqa: F401

from .config import settings
from .factories import gen_default_dev_data
from .queries import ping_db_async_edgeql as ping_db_qry
from .queries import set_default_dev_data_async_edgeql as set_default_dev_data_qry


async def _lifespan(app: FastAPI, registry: svcs.Registry, *, prefill: bool):
Expand All @@ -26,24 +29,27 @@ async def ping_db_callable(_db_client):
ping=ping_db_callable,
)

# Web client
# if prefill:
# http_client = AsyncClient(
# base_url=f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}"
# )
if prefill:
# Web client
# http_client = AsyncClient(
# base_url=f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}"
# )

# async def create_http_client():
# yield http_client
# async def create_http_client():
# yield http_client

# async def ping_http_callable(_http_client):
# return lambda _http_client: _http_client.get("/")
# async def ping_http_callable(_http_client):
# return lambda _http_client: _http_client.get("/")

# registry.register_factory(
# AsyncClient, create_http_client, ping=ping_http_callable
# )
# registry.register_factory(
# AsyncClient, create_http_client, ping=ping_http_callable
# )

yield
await set_default_dev_data_qry.set_default_dev_data(
db_client, data=json.dumps(gen_default_dev_data(n=5))
)

yield
await registry.aclose()


Expand Down
5 changes: 3 additions & 2 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# import sys # noqa: F401
# sys.path.append(os.getcwd())
# import uvicorn # noqa: F401

import httpx # noqa: F401
from asgi_correlation_id import CorrelationIdMiddleware
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

from app import common, events, fixtures, health, users # noqa: F401
from app import common, dev_reset, events, health, users # noqa: F401
from app.config import settings
from app.lifespan import lifespan
from app.logging import setup_logging
Expand Down Expand Up @@ -37,7 +38,7 @@ def make_app(lifespan):
app.include_router(events.router)
app.include_router(health.router)
app.include_router(common.router)
app.include_router(fixtures.router)
app.include_router(dev_reset.router)

# base_url = f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}"
# with httpx.Client(base_url=base_url) as client:
Expand Down
11 changes: 0 additions & 11 deletions app/queries/prepare_dev_data.edgeql

This file was deleted.

17 changes: 17 additions & 0 deletions app/queries/set_default_dev_data.edgeql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
delete Event;
delete User;
with data := <json>$data,
for item in json_array_unpack(data) union (
select (insert Event { name := <str>item['name'],
address := <optional str>item['address'] ?? <str>{},
schedule := <datetime>(<optional str>item['schedule'] ?? <str>{}),
host := (
with host_name:= <str>item['host_name'],
u:= assert_single((select User filter .name = host_name))
select
if exists u then (u)
else (insert User {name:= host_name})
)
}
) {name, address, schedule, host_name:=.host.name}
);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# AUTOGENERATED FROM 'app/queries/prepare_dev_data.edgeql' WITH:
# AUTOGENERATED FROM 'app/queries/set_default_dev_data.edgeql' WITH:
# $ edgedb-py


Expand Down Expand Up @@ -26,19 +26,19 @@ def __get_validators__(cls):


@dataclasses.dataclass
class PrepareDevDataResult(NoPydanticValidation):
class SetDefaultDevDataResult(NoPydanticValidation):
id: uuid.UUID
name: str
address: str | None
schedule: datetime.datetime | None
host_name: str


async def prepare_dev_data(
async def set_default_dev_data(
executor: edgedb.AsyncIOExecutor,
*,
data: str,
) -> list[PrepareDevDataResult]:
) -> list[SetDefaultDevDataResult]:
return await executor.query(
"""\
delete Event;
Expand All @@ -48,9 +48,15 @@ async def prepare_dev_data(
select (insert Event { name := <str>item['name'],
address := <optional str>item['address'] ?? <str>{},
schedule := <datetime>(<optional str>item['schedule'] ?? <str>{}),
host := (insert User {name:= <str>item['host_name']})
}
) {name, address, schedule, host_name:=.host.name}
host := (
with host_name:= <str>item['host_name'],
u:= assert_single((select User filter .name = host_name))
select
if exists u then (u)
else (insert User {name:= host_name})
)
}
) {name, address, schedule, host_name:=.host.name}
);\
""",
data=data,
Expand Down
16 changes: 16 additions & 0 deletions fastui_app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def validate_schedule(cls, v: str | None) -> str | None:
v = (
datetime.datetime.fromisoformat(v)
.astimezone(user_prefer_zoneinfo)
.replace(microsecond=0)
.isoformat()
)
return v
Expand Down Expand Up @@ -211,3 +212,18 @@ class EventUpdateForm(
EventNewNameUpdateForm,
):
pass


################################
# Default Dev Data
################################


class DefaultDevDataForm(BaseModel):
n: int = Field(
title="Number of events",
description="0 <= n_events <=100",
default=5,
ge=0,
le=100,
)
3 changes: 2 additions & 1 deletion fastui_app/lifespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

async def _lifespan(app: FastAPI, registry: svcs.Registry):
backend_client = BackendAsyncClient(
base_url=f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}"
base_url=f"{settings.backend_schema}://{settings.backend_host}:{settings.backend_port}",
timeout=60,
)

async def creat_backend_client():
Expand Down
29 changes: 18 additions & 11 deletions fastui_app/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
FrontendGetAsyncClient,
FrontendPostPutDeleteAsyncClient,
)
from .forms import UserCreationForm, UserUpdateForm
from .forms import DefaultDevDataForm, UserCreationForm, UserUpdateForm
from .shared import demo_page
from .utils import _form_user_repr, _raise_for_status

Expand All @@ -38,9 +38,12 @@ async def user_ilike_searchview(
response_model=FastUI,
response_model_exclude_none=True,
)
async def reset(services: svcs.fastapi.DepContainer):
async def reset(
services: svcs.fastapi.DepContainer,
form: Annotated[DefaultDevDataForm, fastui_form(DefaultDevDataForm)],
):
client = await services.aget(BackendAsyncClient)
resp = await client.post("/fixtures")
resp = await client.post("/reset", json=form.model_dump())
return [c.FireEvent(event=GoToEvent(url="/events/"))]


Expand Down Expand Up @@ -241,28 +244,32 @@ async def user_listview(
),
c.Button(
text="Reset",
on_click=PageEvent(name="reset-dev-data"),
on_click=PageEvent(name="reset-default-dev-data"),
class_name="+ ms-2",
),
c.Modal(
title="Delete User",
title="Reset",
body=[
c.Paragraph(text="Confirm to reset the dev data"),
c.Form(
form_fields=[],
c.Paragraph(text="Confirm to reset as default dev data"),
c.ModelForm(
model=DefaultDevDataForm,
submit_url="/api/reset",
loading=[c.Spinner(text="Resetting...")],
footer=[],
submit_trigger=PageEvent(name="form-reset-dev-data-submit"),
submit_trigger=PageEvent(
name="modal-form-reset-default-dev-data-submit"
),
),
],
footer=[
c.Button(
text="Submit",
on_click=PageEvent(name="form-reset-dev-data-submit"),
on_click=PageEvent(
name="modal-form-reset-default-dev-data-submit"
),
),
],
open_trigger=PageEvent(name="reset-dev-data"),
open_trigger=PageEvent(name="reset-default-dev-data"),
),
],
class_name="mb-3",
Expand Down
15 changes: 15 additions & 0 deletions requirements-ci.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
uvicorn
svcs
edgedb
httpx
fastapi
pytest
pytest-asyncio
pytest-mock
pytest-faker
pytest-repeat
pytest-cov
pydantic-settings
tzdata
structlog
asgi-correlation-id
Loading

0 comments on commit 9a04335

Please sign in to comment.