Skip to content

Commit

Permalink
Add FastAPI example and functionalities guidelines
Browse files Browse the repository at this point in the history
  • Loading branch information
KaQuMiQ authored Oct 18, 2024
1 parent 6612af9 commit 5196e0b
Show file tree
Hide file tree
Showing 36 changed files with 1,303 additions and 8 deletions.
70 changes: 70 additions & 0 deletions examples/fastAPI/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
SHELL := sh
.ONESHELL:
.SHELLFLAGS := -eu -c
.DELETE_ON_ERROR:

SOURCES_PATH := src

# load environment config from .env if able
-include .env

ifndef PYTHON_ALIAS
PYTHON_ALIAS := python
endif

ifndef INSTALL_OPTIONS
INSTALL_OPTIONS := .[dev]
endif

ifndef UV_VERSION
UV_VERSION := 0.4.22
endif

.PHONY: venv sync lock update format lint test run

# Setup virtual environment for local development.
venv:
@echo '# Preparing development environment...'
@echo '...installing uv...'
@curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh
@echo '...preparing venv...'
@$(PYTHON_ALIAS) -m venv .venv --prompt="VENV[DEV]" --clear --upgrade-deps
@. ./.venv/bin/activate && pip install --upgrade pip && uv pip install --editable $(INSTALL_OPTIONS) --constraint constraints
@echo '...development environment ready! Activate venv using `. ./.venv/bin/activate`.'

# Sync environment with uv based on constraints
sync:
@echo '# Synchronizing dependencies...'
@$(if $(findstring $(UV_VERSION), $(shell uv --version | head -n1 | cut -d" " -f2)), , @echo '...updating uv...' && curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh)
@uv pip install --editable $(INSTALL_OPTIONS) --constraint constraints
@echo '...finished!'

# Generate a set of locked dependencies from pyproject.toml
lock:
@echo '# Locking dependencies...'
@uv pip compile pyproject.toml -o constraints --all-extras
@echo '...finished!'

# Update and lock dependencies from pyproject.toml
update:
@echo '# Updating dependencies...'
@$(if $(shell printf '%s\n%s\n' "$(UV_VERSION)" "$$(uv --version | head -n1 | cut -d' ' -f2)" | sort -V | head -n1 | grep -q "$(UV_VERSION)"), , @echo '...updating uv...' && curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh)
# @$(if $(findstring $(UV_VERSION), $(shell uv --version | head -n1 | cut -d" " -f2)), , @echo '...updating uv...' && curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh)
@uv --no-cache pip compile pyproject.toml -o constraints --all-extras --upgrade
@uv pip install --editable $(INSTALL_OPTIONS) --constraint constraints
@echo '...finished!'

# Run formatter.
format:
@ruff check --quiet --fix $(SOURCES_PATH)
@ruff format --quiet $(SOURCES_PATH)

# Run linters and code checks.
lint:
@bandit -r $(SOURCES_PATH)
@ruff check $(SOURCES_PATH)
@pyright --project ./

# Run the server
run:
@python -m server
1 change: 1 addition & 0 deletions examples/fastAPI/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## Haiway FastAPI Example
72 changes: 72 additions & 0 deletions examples/fastAPI/constraints
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# This file was autogenerated by uv via the following command:
# uv --no-cache pip compile pyproject.toml -o constraints --all-extras
annotated-types==0.7.0
# via pydantic
anyio==4.6.2.post1
# via
# httpx
# starlette
asyncpg==0.29.0
# via haiway-fastapi (pyproject.toml)
bandit==1.7.10
# via haiway-fastapi (pyproject.toml)
certifi==2024.8.30
# via
# httpcore
# httpx
click==8.1.7
# via uvicorn
fastapi-slim==0.115.2
# via haiway-fastapi (pyproject.toml)
h11==0.14.0
# via
# httpcore
# uvicorn
haiway==0.1.0
# via haiway-fastapi (pyproject.toml)
httpcore==1.0.6
# via httpx
httpx==0.25.2
# via haiway-fastapi (pyproject.toml)
idna==3.10
# via
# anyio
# httpx
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
nodeenv==1.9.1
# via pyright
pbr==6.1.0
# via stevedore
pydantic==2.9.2
# via fastapi-slim
pydantic-core==2.23.4
# via pydantic
pygments==2.18.0
# via rich
pyright==1.1.385
# via haiway-fastapi (pyproject.toml)
pyyaml==6.0.2
# via bandit
rich==13.9.2
# via bandit
ruff==0.5.7
# via haiway-fastapi (pyproject.toml)
sniffio==1.3.1
# via
# anyio
# httpx
starlette==0.40.0
# via fastapi-slim
stevedore==5.3.0
# via bandit
typing-extensions==4.12.2
# via
# fastapi-slim
# pydantic
# pydantic-core
# pyright
uvicorn==0.32.0
# via haiway-fastapi (pyproject.toml)
61 changes: 61 additions & 0 deletions examples/fastAPI/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "haiway_fastapi"
description = "Example of haiway usage with fastapi."
version = "0.1.0"
readme = "README.md"
maintainers = [
{ name = "Kacper Kaliński", email = "[email protected]" },
]
requires-python = ">=3.12"
dependencies = [
"haiway~=0.1.0",
"fastapi-slim~=0.115",
"asyncpg~=0.29",
"httpx~=0.25.0",
]

[project.urls]
Homepage = "https://miquido.com"

[project.optional-dependencies]
dev = [
"uvicorn~=0.30",
"ruff~=0.5.0",
"pyright~=1.1",
"bandit~=1.7",
]

[tool.ruff]
target-version = "py312"
line-length = 100
extend-exclude = [".venv", ".git", ".cache"]
lint.select = ["E", "F", "A", "I", "B", "PL", "W", "C", "RUF", "UP"]
lint.ignore = []

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401", "E402"]
"./tests/*.py" = ["PLR2004"]

[tool.pyright]
pythonVersion = "3.12"
venvPath = "."
venv = ".venv"
include = ["./src"]
exclude = ["**/node_modules", "**/__pycache__"]
ignore = []
stubPath = "./stubs"
reportMissingImports = true
reportMissingTypeStubs = true
typeCheckingMode = "strict"
userFileIndexingLimit = -1
useLibraryCodeForTypes = true

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["src"]
Empty file.
5 changes: 5 additions & 0 deletions examples/fastAPI/src/features/todos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from features.todos.calls import complete_todo

__all__ = [
"complete_todo",
]
15 changes: 15 additions & 0 deletions examples/fastAPI/src/features/todos/calls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from uuid import UUID

from features.todos.state import Todos
from haiway import ctx

__all__ = [
"complete_todo",
]


async def complete_todo(
*,
identifier: UUID,
) -> None:
await ctx.state(Todos).complete(identifier=identifier)
1 change: 1 addition & 0 deletions examples/fastAPI/src/features/todos/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty
11 changes: 11 additions & 0 deletions examples/fastAPI/src/features/todos/state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from features.todos.types import TodoCompletion
from features.todos.user_tasks import complete_todo_task
from haiway import Structure

__all__ = [
"Todos",
]


class Todos(Structure):
complete: TodoCompletion = complete_todo_task
15 changes: 15 additions & 0 deletions examples/fastAPI/src/features/todos/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Protocol, runtime_checkable
from uuid import UUID

__all__ = [
"TodoCompletion",
]


@runtime_checkable
class TodoCompletion(Protocol):
async def __call__(
self,
*,
identifier: UUID,
) -> None: ...
16 changes: 16 additions & 0 deletions examples/fastAPI/src/features/todos/user_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from uuid import UUID

from haiway import ctx
from solutions.user_tasks import UserTask, UserTasks

__all__ = [
"complete_todo_task",
]


async def complete_todo_task(
*,
identifier: UUID,
) -> None:
task: UserTask = await ctx.state(UserTasks).fetch(identifier=identifier)
await ctx.state(UserTasks).update(task=task.updated(completed=True))
Empty file.
7 changes: 7 additions & 0 deletions examples/fastAPI/src/integrations/postgres/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from integrations.postgres.client import PostgresClient
from integrations.postgres.types import PostgresClientException

__all__ = [
"PostgresClient",
"PostgresClientException",
]
35 changes: 35 additions & 0 deletions examples/fastAPI/src/integrations/postgres/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Self

from haiway import Dependency

from integrations.postgres.config import (
POSTGRES_DATABASE,
POSTGRES_HOST,
POSTGRES_PASSWORD,
POSTGRES_PORT,
POSTGRES_SSLMODE,
POSTGRES_USER,
)
from integrations.postgres.session import PostgresClientSession

__all__ = [
"PostgresClient",
]


class PostgresClient(
PostgresClientSession,
Dependency,
):
@classmethod
async def prepare(cls) -> Self:
instance: Self = cls(
host=POSTGRES_HOST,
port=POSTGRES_PORT,
database=POSTGRES_DATABASE,
user=POSTGRES_USER,
password=POSTGRES_PASSWORD,
ssl=POSTGRES_SSLMODE,
)
await instance.initialize()
return instance
19 changes: 19 additions & 0 deletions examples/fastAPI/src/integrations/postgres/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import Final

from haiway import getenv_str

__all__ = [
"POSTGRES_DATABASE",
"POSTGRES_HOST",
"POSTGRES_PASSWORD",
"POSTGRES_PORT",
"POSTGRES_SSLMODE",
"POSTGRES_USER",
]

POSTGRES_DATABASE: Final[str] = getenv_str("POSTGRES_DATABASE", default="postgres")
POSTGRES_HOST: Final[str] = getenv_str("POSTGRES_HOST", default="localhost")
POSTGRES_PORT: Final[str] = getenv_str("POSTGRES_PORT", default="5432")
POSTGRES_USER: Final[str] = getenv_str("POSTGRES_USER", default="postgres")
POSTGRES_PASSWORD: Final[str] = getenv_str("POSTGRES_PASSWORD", default="postgres")
POSTGRES_SSLMODE: Final[str] = getenv_str("POSTGRES_SSLMODE", default="prefer")
Loading

0 comments on commit 5196e0b

Please sign in to comment.