Add kaya-openapi package for automatic OpenAPI spec generation

- New packages/kaya-openapi with OpenAPIMixin, @operation decorator,
  and generate_spec() that walks the routing tree
- Enables kaya-core's Tree.register to expose the original handler
  callback as an instance attribute for metadata introspection
- Registers GET /openapi.json and GET /docs (Swagger UI) routes
- Supports  and  path parameters, docstring
  descriptions, @operation metadata, and excludes wildcard/WS routes
- Adds example/openapi.py, updates CI, README, and requirements
This commit is contained in:
2026-07-25 09:20:19 +00:00
parent 87d1b0acb1
commit 9a68d10868
14 changed files with 762 additions and 2 deletions
+12 -1
View File
@@ -186,16 +186,27 @@ class Tree:
callback: Callable[[Context, Unpack[Any]], Awaitable[None]],
recursive: bool) -> None:
class Handler(PathHandler):
"""PathHandler created by :meth:`Tree.register`.
The original user callback is exposed through the ``callback``
attribute so that extensions (e.g. ``kaya-openapi``) can inspect
it for metadata such as docstrings or decorator attributes.
"""
callback: Callable[[Context, Unpack[Any]], Awaitable[None]]
async def handle_request(self, ctx: Context, captured: Matches) -> None:
args = Maybe.of_nullable(captured.path).map(lambda it: [it]).or_else([])
await callback(ctx, *args, **captured.kwargs)
await self.callback(ctx, *args, **captured.kwargs)
@property
def recursive(self) -> bool:
return recursive
handler = Handler()
# assigned as an instance attribute (not a class attribute) so that
# the function descriptor protocol does not turn it into a bound method
handler.callback = callback
self.add((p for p in PathIterator(path)), method, handler)
def find_node(self, path: Generator[str, None, None], method: HttpMethod = HttpMethod.GET) \