chore(release): 0.0.7

Squash-merge lib-standardisation: adopt repo standards across packaging,
tooling, docs, and CI.

- standardize pyproject.toml (canonical packaging, lint config, extras, GSDFC pydoclint)
- add py.typed marker, modernize type hints and Google-style docstrings
- nest generated docs under docs/lib and docs/mcp; add hand-written wiki
- adopt standard Type A PyPI CI pipeline (tag==version guard + quality gate)
- promote generated CHANGELOG.md; bump version to 0.0.7
This commit is contained in:
2026-10-17 02:16:49 +05:30
parent c95de5a6e9
commit 621f10409e
162 changed files with 10165 additions and 2846 deletions

View File

@@ -1,17 +1,21 @@
"""
# Summary
OpenAPI security scheme parsing and auto-generated auth dependencies.
Reads `securitySchemes` and per-operation `security` from an OpenAPI spec,
resolves `{ENV_VAR}` placeholders in `x-` extension fields, and generates
FastAPI dependencies for token validation (e.g., Bearer JWT introspection).
This module reads `securitySchemes` and per-operation `security` from an
OpenAPI spec, resolves `{ENV_VAR}` placeholders in `x-` extension fields,
and generates FastAPI dependencies for token validation (e.g., Bearer JWT
introspection).
"""
import os
import re
from typing import Any, Callable
from collections.abc import Callable
from typing import Any
import httpx
from fastapi import Depends, Request, HTTPException
from fastapi import Depends, HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
_env_pattern = re.compile(r"\{(\w+)\}")
@@ -19,14 +23,16 @@ _env_pattern = re.compile(r"\{(\w+)\}")
def _resolve_env(value: str) -> str:
"""Replace {ENV_VAR} placeholders with values from os.environ."""
def _replace(m: re.Match) -> str:
def _replace(m: re.Match[str]) -> str:
return os.environ.get(m.group(1), "")
return _env_pattern.sub(_replace, value)
def _resolve_scheme(scheme: dict) -> dict:
def _resolve_scheme(scheme: dict[str, Any]) -> dict[str, Any]:
"""Recursively resolve env vars in all string-valued fields of a scheme."""
resolved = {}
resolved: dict[str, Any] = {}
for key, value in scheme.items():
if isinstance(value, str):
resolved[key] = _resolve_env(value)
@@ -37,13 +43,13 @@ def _resolve_scheme(scheme: dict) -> dict:
return resolved
def parse_security_schemes(spec: dict) -> dict[str, dict]:
def parse_security_schemes(spec: dict[str, Any]) -> dict[str, dict[str, Any]]:
"""Extract and resolve environment variables in security schemes."""
raw = spec.get("components", {}).get("securitySchemes", {})
return {name: _resolve_scheme(scheme) for name, scheme in raw.items()}
def _make_bearer_dependency(introspect_url: str | None) -> Callable:
def _make_bearer_dependency(introspect_url: str | None) -> Callable[..., Any]:
"""
Create a FastAPI dependency that validates a Bearer JWT.
@@ -76,7 +82,7 @@ def _make_bearer_dependency(introspect_url: str | None) -> Callable:
raise HTTPException(
status_code=503,
detail="Authentication service unavailable",
)
) from None
if resp.status_code != 200:
raise HTTPException(status_code=401, detail="Invalid or expired token")
@@ -92,7 +98,9 @@ def _make_bearer_dependency(introspect_url: str | None) -> Callable:
return _bearer_dep
def _build_dependency(scheme_name: str, scheme: dict) -> Callable | None:
def _build_dependency(
scheme_name: str, scheme: dict[str, Any]
) -> Callable[..., Any] | None:
"""Return a FastAPI dependency callable for *scheme*, or ``None``."""
scheme_type = scheme.get("type")
@@ -106,8 +114,8 @@ def _build_dependency(scheme_name: str, scheme: dict) -> Callable | None:
def make_security_dependencies(
spec: dict,
security_schemes: dict[str, dict],
spec: dict[str, Any],
security_schemes: dict[str, dict[str, Any]],
) -> dict[str, list[Any]]:
"""
Build a mapping of ``METHOD:/path`` → list of ``Depends(...)``.