Skip to content

Commit

Permalink
Add a flavor setting to FastAPI Safir app template
Browse files Browse the repository at this point in the history
Rather than a boolean saying whether or not the service in question
is a UWS service, instead add a new flavor key that currently takes
only two values: Default and UWS. Change all the conditionals to
instead check that the flavor is UWS to enable the UWS code.
  • Loading branch information
rra committed Jul 30, 2024
1 parent 6c97b25 commit 3ec9f41
Show file tree
Hide file tree
Showing 23 changed files with 48 additions and 45 deletions.
2 changes: 1 addition & 1 deletion project_templates/fastapi_safir_app/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ env.Cookiecutter(AlwaysBuild(Dir('example')),
env.Cookiecutter(AlwaysBuild(Dir('example-uws')),
'cookiecutter.json',
cookiecutter_context={'name': 'example-uws',
'uws_service': 'True'})
'flavor': 'UWS'})
5 changes: 4 additions & 1 deletion project_templates/fastapi_safir_app/cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"lsst-dm",
"lsst-sqre-testing"
],
"uws_service": ["False", "True"],
"flavor": [
"Default",
"UWS"
],
"_extensions": ["jinja2_time.TimeExtension", "templatekit.TemplatekitExtension"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import shutil

# These variables are interpolated by cookiecutter before this hook is run
uws_service = True if '{{ cookiecutter.uws_service }}' == 'True' else False
uws_service = True if '{{ cookiecutter.flavor }}' == 'UWS' else False
module_name = '{{ cookiecutter.module_name }}'
github_org = '{{ cookiecutter.github_org }}'

Expand Down
8 changes: 4 additions & 4 deletions project_templates/fastapi_safir_app/templatekit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ dialog_fields:
label: "GitHub organization"
hint: "The package will be created in this GitHub organization."
component: "select"
- key: "flavor"
label: "Flavor"
hint: "Flavor of FastAPI service to create."
component: "select"
- label: "Initial copyright holder"
key: "copyright_holder"
component: "select"
- label: "UWS service"
key: "uws_service"
hint: "Select True if this is an IVOA UWS service with a separate worker."
component: "select"
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
with:
image: {{ "${{ github.repository }}" }}
github_token: {{ "${{ secrets.GITHUB_TOKEN }}" }}
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}

- uses: lsst-sqre/build-and-push-to-ghcr@v1
id: build-worker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
# This Dockerfile constructs the image for backend workers. These images
# are based on stack containers and install any required supporting code
# for the backend, arq, and the backend worker definition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ uvicorn[standard]
# Other dependencies.
pydantic
pydantic-settings
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
safir[uws]>=7
{%- else %}
safir>=5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
-c dev.txt

tox
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
tox-docker
{%- endif %}
tox-uv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
#!/bin/bash

# Install or upgrade any operating system packages needed on worker images.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
#!/bin/bash

# This script updates and installs the necessary prerequisites for a backend
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
#!/bin/bash

# This script is installed in the worker image and starts the backend worker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
"""Administrative command-line interface."""

from __future__ import annotations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from __future__ import annotations

from pydantic import Field
from pydantic_settings import {% if cookiecutter.uws_service != 'True' %}BaseSettings, {% endif %}SettingsConfigDict
from pydantic_settings import {% if cookiecutter.flavor != "UWS" %}BaseSettings, {% endif %}SettingsConfigDict
from safir.logging import LogLevel, Profile
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
from safir.uws import UWSApplication, UWSAppSettings, UWSConfig, UWSRoute

from .dependencies import post_params_dependency
Expand All @@ -15,7 +15,7 @@
__all__ = ["Config", "config"]


class Config({% if cookiecutter.uws_service == 'True' %}UWSAppSettings{% else %}BaseSettings{% endif %}):
class Config({% if cookiecutter.flavor == "UWS" %}UWSAppSettings{% else %}BaseSettings{% endif %}):
"""Configuration for {{ cookiecutter.name }}."""

name: str = Field("{{ cookiecutter.name }}", title="Name of application")
Expand All @@ -35,7 +35,7 @@ class Config({% if cookiecutter.uws_service == 'True' %}UWSAppSettings{% else %}
model_config = SettingsConfigDict(
env_prefix="{{ cookiecutter.name | upper | replace('-', '_') }}_", case_sensitive=False
)
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}

@property
def uws_config(self) -> UWSConfig:
Expand All @@ -54,7 +54,7 @@ def uws_config(self) -> UWSConfig:

config = Config()
"""Configuration for {{ cookiecutter.name }}."""
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}

uws = UWSApplication(config.uws_config)
"""The UWS application for this service."""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
"""Job parameter dependencies."""

from typing import Annotated
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
"""Domain models for {{ cookiecutter.name }}."""

from __future__ import annotations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from safir.logging import configure_logging, configure_uvicorn_logging
from safir.middleware.x_forwarded import XForwardedMiddleware

from .config import config{% if cookiecutter.uws_service == "True" %}, uws{% endif %}
from .config import config{% if cookiecutter.flavor == "UWS" %}, uws{% endif %}
from .handlers.external import external_router
from .handlers.internal import internal_router

Expand All @@ -27,14 +27,14 @@
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
"""Set up and tear down the application."""
# Any code here will be run when the application starts up.
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
await uws.initialize_fastapi()
{%- endif %}

yield

# Any code here will be run when the application shuts down.
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
await uws.shutdown_fastapi()
{%- endif %}
await http_client_dependency.aclose()
Expand All @@ -60,14 +60,14 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:

# Attach the routers.
app.include_router(internal_router)
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
uws.install_handlers(external_router)
{%- endif %}
app.include_router(external_router, prefix=f"{config.path_prefix}")

# Add middleware.
app.add_middleware(XForwardedMiddleware)
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
uws.install_middleware(app)

# Install error handlers.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Models for {{ cookiecutter.name }}."""

{% if cookiecutter.uws_service == "True" -%}
{% if cookiecutter.flavor == "UWS" -%}
from typing import Self

{% endif -%}
from pydantic import BaseModel, Field
from safir.metadata import Metadata as SafirMetadata
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
from safir.uws import ParametersModel, UWSJobParameter

from .domain import Worker{{ cookiecutter.module_name | capitalize }}Model
Expand All @@ -27,7 +27,7 @@ class Index(BaseModel):
"""

metadata: SafirMetadata = Field(..., title="Package metadata")
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}


class {{ cookiecutter.module_name | capitalize }}Parameters(ParametersModel[Worker{{ cookiecutter.module_name | capitalize }}Model]):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
"""Worker for UWS database updates."""

from __future__ import annotations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if cookiecutter.uws_service == "True" -%}
{%- if cookiecutter.flavor == "UWS" -%}
"""Worker for {{ cookiecutter.name }}.
This is a standalone file intended to be injected into a stack container as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@

from __future__ import annotations

from collections.abc import AsyncIterator{% if cookiecutter.uws_service == "True" %}, Iterator
from collections.abc import AsyncIterator{% if cookiecutter.flavor == "UWS" %}, Iterator
from datetime import timedelta
{%- endif %}

{% if cookiecutter.uws_service == "True" -%}
{% if cookiecutter.flavor == "UWS" -%}
import pytest
{% endif -%}
import pytest_asyncio
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
import structlog
{%- endif %}
from asgi_lifespan import LifespanManager
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
from safir.arq import MockArqQueue
from safir.testing.gcs import MockStorageClient, patch_google_storage
from safir.testing.uws import MockUWSJobRunner
{%- endif %}

from {{ cookiecutter.module_name }} import main
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
from {{ cookiecutter.module_name }}.config import config, uws
{%- endif %}


@pytest_asyncio.fixture
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
async def app(arq_queue: MockArqQueue) -> AsyncIterator[FastAPI]:
{%- else %}
async def app() -> AsyncIterator[FastAPI]:
Expand All @@ -39,14 +39,14 @@ async def app() -> AsyncIterator[FastAPI]:
Wraps the application in a lifespan manager so that startup and shutdown
events are sent during test execution.
"""
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}
logger = structlog.get_logger("{{ cookiecutter.module_name }}")
await uws.initialize_uws_database(logger, reset=True)
uws.override_arq_queue(arq_queue)
{%- endif %}
async with LifespanManager(main.app):
yield main.app
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}


@pytest.fixture
Expand All @@ -63,7 +63,7 @@ async def client(app: FastAPI) -> AsyncIterator[AsyncClient]:
base_url="https://example.com/",
) as client:
yield client
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}


@pytest.fixture(autouse=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
envlist = py,coverage-report,typing,lint
isolated_build = True
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}

[docker:postgres]
image = postgres:latest
Expand Down Expand Up @@ -36,7 +36,7 @@ deps = coverage[toml]>=5.0.2
depends =
py
commands = coverage report
{%- if cookiecutter.uws_service == "True" %}
{%- if cookiecutter.flavor == "UWS" %}

[testenv:py]
docker =
Expand Down
2 changes: 1 addition & 1 deletion project_templates/technote_md/testn-000/technote.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ series_id = "TESTN"
canonical_url = "https://testn-000.lsst.io"
github_url = "https://github.com/lsst/testn-000"
github_default_branch = "main"
date_created = 2024-07-30T22:02:34Z
date_created = 2024-07-30T22:22:53Z
organization.name = "Vera C. Rubin Observatory"
organization.ror = "https://ror.org/048g3cy84"
license.id = "CC-BY-4.0"
Expand Down
2 changes: 1 addition & 1 deletion project_templates/technote_rst/testn-000/technote.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ series_id = "TESTN"
canonical_url = "https://testn-000.lsst.io"
github_url = "https://github.com/lsst/testn-000"
github_default_branch = "main"
date_created = 2024-07-30T22:02:34Z
date_created = 2024-07-30T22:22:53Z
organization.name = "Vera C. Rubin Observatory"
organization.ror = "https://ror.org/048g3cy84"
license.id = "CC-BY-4.0"
Expand Down

0 comments on commit 3ec9f41

Please sign in to comment.