Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/test_and_publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:

env:
DEFAULT_LINUX: "slim"
DEFAULT_PYTHON: "3.13"
DEFAULT_PYTHON: "3.14"
DEFAULT_SCHEMAS: "pydantic"

jobs:
Expand All @@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@master
with:
Expand Down Expand Up @@ -110,7 +110,7 @@ jobs:
strategy:
matrix:
linux: ["slim"]
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
schemas: ["pydantic", "marshmallow", "typesystem"]
steps:
- name: Check out the repo
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_pull_request_branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@master
with:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repos:
- id: name-tests-test
args:
- --django
exclude: "asserts.py|utils.py"
exclude: "_utils/.*"
- id: pretty-format-json
args:
- --autofix
Expand Down
6 changes: 3 additions & 3 deletions examples/add_model_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pydantic

import flama
from flama import Flama, schemas
from flama import Flama, types
from flama.models import ModelResource
from flama.resources import ResourceRoute

Expand Down Expand Up @@ -46,8 +46,8 @@ class MySKModel(ModelResource):

@ResourceRoute.method("/predict/", methods=["POST"], name="model-predict")
def predict(
self, data: t.Annotated[schemas.SchemaType, schemas.SchemaMetadata(X)]
) -> t.Annotated[schemas.SchemaType, schemas.SchemaMetadata(Y)]:
self, data: t.Annotated[types.Schema, types.SchemaMetadata(X)]
) -> t.Annotated[types.Schema, types.SchemaMetadata(Y)]:
"""
tags:
- My ScikitLearn Model
Expand Down
8 changes: 4 additions & 4 deletions examples/data_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pydantic

import flama
from flama import Flama, schemas
from flama import Flama, types

app = Flama(
openapi={
Expand Down Expand Up @@ -38,7 +38,7 @@ def home():
return {"hello": "world"}


def list_puppies(name: t.Optional[str] = None) -> t.Annotated[list[schemas.SchemaType], schemas.SchemaMetadata(Puppy)]:
def list_puppies(name: str | None = None) -> t.Annotated[types.SchemaList, types.SchemaMetadata(Puppy)]:
"""
tags:
- puppy
Expand All @@ -55,8 +55,8 @@ def list_puppies(name: t.Optional[str] = None) -> t.Annotated[list[schemas.Schem


def create_puppy(
puppy: t.Annotated[schemas.SchemaType, schemas.SchemaMetadata(Puppy)],
) -> t.Annotated[schemas.SchemaType, schemas.SchemaMetadata(Puppy)]:
puppy: t.Annotated[types.Schema, types.SchemaMetadata(Puppy)],
) -> t.Annotated[types.Schema, types.SchemaMetadata(Puppy)]:
"""
tags:
- puppy
Expand Down
3 changes: 1 addition & 2 deletions examples/pagination.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import string
import typing as t

import pydantic

Expand Down Expand Up @@ -67,7 +66,7 @@ def alphabet(**kwargs):


@app.route("/puppy/", methods=["GET"], pagination="page_number")
def puppies(name: t.Optional[str] = None, **kwargs) -> list[Puppy]:
def puppies(name: str | None = None, **kwargs) -> list[Puppy]:
"""
tags:
- puppy
Expand Down
122 changes: 59 additions & 63 deletions flama/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from flama import asgi, exceptions, http, injection, routing, types, url, validation, websockets
from flama.ddd.components import WorkerComponent
from flama.events import Events
from flama.injection.components import Components
from flama.middleware import MiddlewareStack
from flama.models.modules import ModelsModule
from flama.modules import Modules
Expand Down Expand Up @@ -35,13 +36,13 @@ class Flama:
def __init__(
self,
*,
routes: t.Optional[t.Sequence["routing.BaseRoute"]] = None,
components: t.Optional[t.Union[t.Sequence[injection.Component], set[injection.Component]]] = None,
modules: t.Optional[t.Union[t.Sequence["Module"], set["Module"]]] = None,
middleware: t.Optional[t.Sequence["Middleware"]] = None,
routes: t.Sequence[routing.BaseRoute] | None = None,
components: t.Sequence[injection.Component] | set[injection.Component] | None = None,
modules: t.Sequence["Module"] | set["Module"] | None = None,
middleware: t.Sequence["Middleware"] | None = None,
debug: bool = False,
events: t.Optional[t.Union[dict[str, list[t.Callable[..., t.Coroutine[t.Any, t.Any, None]]]], Events]] = None,
lifespan: t.Optional[t.Callable[[t.Optional["Flama"]], t.AsyncContextManager]] = None,
events: dict[str, list[t.Callable[..., t.Coroutine[t.Any, t.Any, None]]]] | Events | None = None,
lifespan: t.Callable[["Flama | None"], t.AsyncContextManager] | None = None,
openapi: types.OpenAPISpec = {
"info": {
"title": "Flama",
Expand All @@ -50,9 +51,10 @@ def __init__(
"description": "Firing up with the flame",
},
},
schema: t.Optional[str] = "/schema/",
docs: t.Optional[str] = "/docs/",
schema_library: t.Optional[str] = None,
schema: str | None = "/schema/",
docs: str | None = "/docs/",
schema_library: str | None = None,
parent: "Flama | None" = None,
) -> None:
"""Flama application.

Expand All @@ -63,17 +65,19 @@ def __init__(
:param debug: Debug mode.
:param events: Handlers that will be triggered after certain events.
:param lifespan: Lifespan function.
:param title: API title.
:param version: API version.
:param description: API description.
:param openapi: OpenAPI spec.
:param schema: OpenAPI schema endpoint path.
:param docs: Docs endpoint path.
:param schema_library: Schema library to use.
:param parent: Parent app.
"""
self._debug = debug
self._status = types.AppStatus.NOT_STARTED
self._shutdown = False

# Sets parent app
self.parent = parent

# Create Dependency Injector
self._injector = injection.Injector(Context)

Expand All @@ -94,7 +98,7 @@ def __init__(

# Initialize router
self.app = self.router = routing.Router(
routes=routes, components=[*default_components, *(components or [])], lifespan=lifespan
routes=routes, components=[*default_components, *(components or [])], lifespan=lifespan, app=self
)

# Build middleware stack
Expand All @@ -114,9 +118,6 @@ def __init__(
# Reference to paginator from within app
self.paginator = paginator

# Build router to propagate root application
self.router.build(self)

def __getattr__(self, item: str) -> t.Any:
"""Retrieve a module by its name.

Expand Down Expand Up @@ -159,22 +160,21 @@ def status(self, s: types.AppStatus) -> None:

@property
def components(self) -> injection.Components:
"""Components register.
"""List of available components for this application.

:return: Components register.
:return: Available components.
"""
return self.router.components
return Components(self.router.components + (self.parent.components if self.parent else ()))

def add_component(self, component: injection.Component):
"""Add a new component to the register.

:param component: Component to include.
"""
self.router.add_component(component)
self.router.build(self)

@property
def routes(self) -> list["routing.BaseRoute"]:
def routes(self) -> list[routing.BaseRoute]:
"""List of registered routes.

:return: Routes.
Expand All @@ -183,15 +183,16 @@ def routes(self) -> list["routing.BaseRoute"]:

def add_route(
self,
path: t.Optional[str] = None,
endpoint: t.Optional[types.HTTPHandler] = None,
methods: t.Optional[list[str]] = None,
name: t.Optional[str] = None,
path: str | None = None,
endpoint: types.HTTPHandler | None = None,
methods: list[str] | None = None,
*,
name: str | None = None,
include_in_schema: bool = True,
route: t.Optional["routing.Route"] = None,
pagination: t.Optional[types.Pagination] = None,
tags: t.Optional[dict[str, t.Any]] = None,
) -> "routing.Route":
route: routing.Route | None = None,
pagination: types.Pagination | None = None,
tags: dict[str, t.Any] | None = None,
) -> routing.Route:
"""Register a new HTTP route or endpoint under given path.

:param path: URL path.
Expand All @@ -210,19 +211,19 @@ def add_route(
name=name,
include_in_schema=include_in_schema,
route=route,
root=self,
pagination=pagination,
tags=tags,
)

def route(
self,
path: str,
methods: t.Optional[list[str]] = None,
name: t.Optional[str] = None,
methods: list[str] | None = None,
*,
name: str | None = None,
include_in_schema: bool = True,
pagination: t.Optional[types.Pagination] = None,
tags: t.Optional[dict[str, t.Any]] = None,
pagination: types.Pagination | None = None,
tags: dict[str, t.Any] | None = None,
) -> t.Callable[[types.HTTPHandler], types.HTTPHandler]:
"""Decorator version for registering a new HTTP route in this router under given path.

Expand All @@ -235,24 +236,19 @@ def route(
:return: Decorated route.
"""
return self.router.route(
path,
methods=methods,
name=name,
include_in_schema=include_in_schema,
root=self,
pagination=pagination,
tags=tags,
path, methods=methods, name=name, include_in_schema=include_in_schema, pagination=pagination, tags=tags
)

def add_websocket_route(
self,
path: t.Optional[str] = None,
endpoint: t.Optional[types.WebSocketHandler] = None,
name: t.Optional[str] = None,
route: t.Optional["routing.WebSocketRoute"] = None,
pagination: t.Optional[types.Pagination] = None,
tags: t.Optional[dict[str, t.Any]] = None,
) -> "routing.WebSocketRoute":
path: str | None = None,
endpoint: types.WebSocketHandler | None = None,
*,
name: str | None = None,
route: routing.WebSocketRoute | None = None,
pagination: types.Pagination | None = None,
tags: dict[str, t.Any] | None = None,
) -> routing.WebSocketRoute:
"""Register a new websocket route or endpoint under given path.

:param path: URL path.
Expand All @@ -262,16 +258,15 @@ def add_websocket_route(
:param pagination: Apply a pagination technique.
:param tags: Tags to add to the websocket route.
"""
return self.router.add_websocket_route(
path, endpoint, name=name, route=route, root=self, pagination=pagination, tags=tags
)
return self.router.add_websocket_route(path, endpoint, name=name, route=route, pagination=pagination, tags=tags)

def websocket_route(
self,
path: str,
name: t.Optional[str] = None,
pagination: t.Optional[types.Pagination] = None,
tags: t.Optional[dict[str, t.Any]] = None,
*,
name: str | None = None,
pagination: types.Pagination | None = None,
tags: dict[str, t.Any] | None = None,
) -> t.Callable[[types.WebSocketHandler], types.WebSocketHandler]:
"""Decorator version for registering a new websocket route in this router under given path.

Expand All @@ -281,16 +276,17 @@ def websocket_route(
:param tags: Tags to add to the websocket route.
:return: Decorated route.
"""
return self.router.websocket_route(path, name=name, root=self, pagination=pagination, tags=tags)
return self.router.websocket_route(path, name=name, pagination=pagination, tags=tags)

def mount(
self,
path: t.Optional[str] = None,
app: t.Optional[types.App] = None,
name: t.Optional[str] = None,
mount: t.Optional["routing.Mount"] = None,
tags: t.Optional[dict[str, t.Any]] = None,
) -> "routing.Mount":
path: str | None = None,
app: types.App | None = None,
*,
name: str | None = None,
mount: routing.Mount | None = None,
tags: dict[str, t.Any] | None = None,
) -> routing.Mount:
"""Register a new mount point containing an ASGI app in this router under given path.

:param path: URL path.
Expand All @@ -300,7 +296,7 @@ def mount(
:param tags: Tags to add to the mount.
:return: Mount.
"""
return self.router.mount(path, app, name=name, mount=mount, root=self, tags=tags)
return self.router.mount(path, app, name=name, mount=mount, tags=tags)

@property
def injector(self) -> injection.Injector:
Expand Down Expand Up @@ -334,7 +330,7 @@ def decorator(func: t.Callable) -> t.Callable:

return decorator

def add_exception_handler(self, exc_class_or_status_code: t.Union[int, type[Exception]], handler: t.Callable):
def add_exception_handler(self, exc_class_or_status_code: int | type[Exception], handler: t.Callable):
"""Add a new exception handler for given status code or exception class.

:param exc_class_or_status_code: Status code or exception class.
Expand Down
Loading