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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ third-party Actions alike.
**Rationale.** Mutable tags (including immutable-looking version tags
like `@v6.0.1`) can be retroactively moved by an attacker who gains
write access to the upstream repository. The
[`tj-actions/changed-files` compromise (CVE-2025-30066, March 2025)](https://www.cisa.gov/news-events/alerts/2025/03/18/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066)
[`tj-actions/changed-files` compromise (CVE-2025-30066, March 2025)](https://github.com/advisories/GHSA-mrrh-fwg8-r2c3)
demonstrated this exact failure mode: ~23,000 repositories had their CI
secrets exfiltrated, and only workflows that pinned to a commit SHA were
safe. GitHub's own guidance now identifies SHA pinning as
Expand Down
10 changes: 5 additions & 5 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ Note: `render_swagger_ui()` does not embed or generate the OpenAPI spec. It retu

## See Also

- [azure-functions-validation — Architecture](https://github.com/yeongseon/azure-functions-validation) — Request/response validation pipeline
- [azure-functions-logging — Architecture](https://github.com/yeongseon/azure-functions-logging) — Structured logging with contextvars
- [azure-functions-doctor — Architecture](https://github.com/yeongseon/azure-functions-doctor) — Pre-deploy diagnostic CLI
- [azure-functions-scaffold — Architecture](https://github.com/yeongseon/azure-functions-scaffold) — Project scaffolding CLI
- [azure-functions-langgraph — Architecture](https://github.com/yeongseon/azure-functions-langgraph) — LangGraph agent deployment
- [azure-functions-validation — Architecture](https://github.com/yeongseon/azure-functions-validation-python) — Request/response validation pipeline
- [azure-functions-logging — Architecture](https://github.com/yeongseon/azure-functions-logging-python) — Structured logging with contextvars
- [azure-functions-doctor — Architecture](https://github.com/yeongseon/azure-functions-doctor-python) — Pre-deploy diagnostic CLI
- [azure-functions-scaffold — Architecture](https://github.com/yeongseon/azure-functions-scaffold-python) — Project scaffolding CLI
- [azure-functions-langgraph — Architecture](https://github.com/yeongseon/azure-functions-langgraph-python) — LangGraph agent deployment
2 changes: 1 addition & 1 deletion SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Supported Environment

* Python: 3.11 and above
* Python: 3.11-3.14 (`>=3.11,<3.15`)
* Runtime: Azure Functions (Python)

## Support Scope
Expand Down
12 changes: 6 additions & 6 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ The `_openapi_registry` is protected by `threading.RLock`, ensuring safe concurr

The function accepts a similar core metadata shape to `@openapi(...)` (path, method, operation_id, summary, request/response schemas, etc.) and writes directly to the shared `_openapi_registry`. Once registered, routes appear in the generated spec alongside decorator-registered routes.

**Reference consumer:** [`azure-functions-langgraph`](https://github.com/yeongseon/azure-functions-langgraph) uses its bridge module (`azure_functions_langgraph.openapi.register_with_openapi`) to read route metadata from its `get_app_metadata()` API and forward it to `register_openapi_metadata()`. This pattern demonstrates how any Azure Functions package can contribute routes to the OpenAPI spec without depending on the `@openapi` decorator.
**Reference consumer:** [`azure-functions-langgraph`](https://github.com/yeongseon/azure-functions-langgraph-python) uses its bridge module (`azure_functions_langgraph.openapi.register_with_openapi`) to read route metadata from its `get_app_metadata()` API and forward it to `register_openapi_metadata()`. This pattern demonstrates how any Azure Functions package can contribute routes to the OpenAPI spec without depending on the `@openapi` decorator.

The architecture intentionally keeps bridge implementation in the *consumer* package (langgraph), not here. This package defines the contract; consumers decide when and how to call it.

Expand Down Expand Up @@ -260,8 +260,8 @@ The architecture intentionally keeps bridge implementation in the *consumer* pac

## See Also

- [azure-functions-langgraph — Architecture](https://github.com/yeongseon/azure-functions-langgraph) — LangGraph deployment adapter (reference consumer of `register_openapi_metadata()`)
- [azure-functions-validation — Architecture](https://github.com/yeongseon/azure-functions-validation) — Request/response validation pipeline
- [azure-functions-logging — Architecture](https://github.com/yeongseon/azure-functions-logging) — Structured logging with contextvars
- [azure-functions-doctor — Architecture](https://github.com/yeongseon/azure-functions-doctor) — Pre-deploy diagnostic CLI
- [azure-functions-scaffold — Architecture](https://github.com/yeongseon/azure-functions-scaffold) — Project scaffolding CLI
- [azure-functions-langgraph — Architecture](https://github.com/yeongseon/azure-functions-langgraph-python) — LangGraph deployment adapter (reference consumer of `register_openapi_metadata()`)
- [azure-functions-validation — Architecture](https://github.com/yeongseon/azure-functions-validation-python) — Request/response validation pipeline
- [azure-functions-logging — Architecture](https://github.com/yeongseon/azure-functions-logging-python) — Structured logging with contextvars
- [azure-functions-doctor — Architecture](https://github.com/yeongseon/azure-functions-doctor-python) — Pre-deploy diagnostic CLI
- [azure-functions-scaffold — Architecture](https://github.com/yeongseon/azure-functions-scaffold-python) — Project scaffolding CLI
15 changes: 15 additions & 0 deletions docs/assets/screenshots.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Screenshot provenance manifest.
#
# STATUS: every capture below is HISTORICAL. All images were taken at
# package version 0.21.2 (2026-08-15) and have not been re-captured since.
# They still illustrate the documented behaviour, but chrome, labels, and
# minor spec details may differ from the current release. Re-capture and run
# `python scripts/check_screenshots.py --update` before relying on them as a
# pixel-accurate reference for the latest version.
schema_version: 1
screenshots:
- id: deployment_report_jobs_openapi_json
Expand All @@ -7,6 +15,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/report_jobs/function_app.py
Expand All @@ -20,6 +29,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/report_jobs/function_app.py
Expand All @@ -33,6 +43,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/notification_request/function_app.py
Expand All @@ -46,6 +57,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/partner_import_bridge/function_app.py
Expand All @@ -59,6 +71,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/webhook_receiver/function_app.py
Expand All @@ -72,6 +85,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/webhook_receiver/function_app.py
Expand All @@ -85,6 +99,7 @@ screenshots:
git_sha: 8310039aa73e91d45cc8389b356428071225eb5b
date: '2026-08-15'
method: manual
status: historical
source:
inputs:
- examples/webhook_receiver/function_app.py
Expand Down
38 changes: 23 additions & 15 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Titles for issues, pull requests, and commits follow the **Title Convention** in
### Before submitting

- Run `make check-all` and verify it passes.
- Ensure new code has test coverage (target: 85%+).
- Ensure new code has test coverage. The suite is gated at 95% (`fail_under = 95` in `pyproject.toml`).
- Update documentation if the change affects public API or behavior.
- Keep the PR focused on a single concern.

Expand All @@ -82,17 +82,16 @@ Describe what changed and why. Reference related issues with `Fixes #N` or `Clos

### Review process

- At least one approval is required before merging.
- Branch protection does not require a review approval; the required CI checks are the merge gate. Maintainers still review anything beyond a trivial change.
- CI must pass on all Python versions (3.11 -- 3.14).
- Merge with "Squash and merge" to keep the commit history clean.

## Code Style

### Formatting

- **Black** for code formatting (line length: default).
- **Ruff** for linting and import sorting.
- Both run as pre-commit hooks.
- **Ruff** does everything: formatting, linting, and import sorting. There is no Black in this project.
- `ruff format` and `ruff check` both run as pre-commit hooks.

### Type annotations

Expand All @@ -115,22 +114,31 @@ Describe what changed and why. Reference related issues with `Fixes #N` or `Clos

| Target | Description |
| --- | --- |
| `make format` | Format code with Ruff and Black |
| `make lint` | Run Ruff linter |
| `make format` | Format code with `ruff format` |
| `make format-check` | Check formatting without writing |
| `make style` | `ruff check` + `ruff format --check` |
| `make lint` | Run Ruff + mypy |
| `make typecheck` | Run mypy type checking |
| `make security` | Run Bandit security scan |
| `make test` | Run pytest |
| `make cov` | Run tests with coverage |
| `make check-all` | Run lint + typecheck + test (full gate) |
| `make cov` | Run tests with coverage (gated at 95%) |
| `make lint-workflows` | Lint release workflows, action pins, Hatch matrix |
| `make check` | Run lint + typecheck |
| `make check-all` | Run lint-workflows + check + test + security (full gate) |
| `make docs` | Build the MkDocs site |

See [Development Guide](development.md#makefile-targets) for the complete list.

### Pre-commit hooks

| Tool | Version | Purpose |
| --- | --- | --- |
| Black | 26.1.0 | Code formatter |
| Ruff | v0.14.13 | Linter and import sorter |
| mypy | v1.19.1 | Static type checker |
| Bandit | 1.9.3 | Security scanner (src/ only) |
| Tool | Purpose |
| --- | --- |
| Ruff | Formatter, linter, and import sorter |
| mypy | Static type checker |
| Bandit | Security scanner (`src/` only) |

Pinned versions live in `.pre-commit-config.yaml` (hook `rev`) and
`pyproject.toml` (the `dev` dependency pins), so they are not duplicated here.

Run all hooks manually:

Expand Down
14 changes: 7 additions & 7 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ From either example directory:

```bash
azure-functions-openapi generate \
--app-path ./function_app.py \
--app function_app:app \
--format json \
--output ./openapi.json
```
Expand All @@ -398,7 +398,7 @@ Generate YAML instead:

```bash
azure-functions-openapi generate \
--app-path ./function_app.py \
--app function_app:app \
--format yaml \
--output ./openapi.yaml
```
Expand Down Expand Up @@ -535,8 +535,8 @@ az group list --query "[?starts_with(name, 'rg-openapi')]" -o table

- [Choose an Azure Functions Hosting Plan](choose-a-plan.md) — Plan selection guide with decision tree
- [CLI guide](./cli.md)
- [`azure-functions-scaffold`](https://github.com/yeongseon/azure-functions-scaffold)
- [`azure-functions-validation`](https://github.com/yeongseon/azure-functions-validation)
- [`azure-functions-doctor`](https://github.com/yeongseon/azure-functions-doctor)
- [`azure-functions-logging`](https://github.com/yeongseon/azure-functions-logging)
- [`azure-functions-langgraph`](https://github.com/yeongseon/azure-functions-langgraph)
- [`azure-functions-scaffold`](https://github.com/yeongseon/azure-functions-scaffold-python)
- [`azure-functions-validation`](https://github.com/yeongseon/azure-functions-validation-python)
- [`azure-functions-doctor`](https://github.com/yeongseon/azure-functions-doctor-python)
- [`azure-functions-logging`](https://github.com/yeongseon/azure-functions-logging-python)
- [`azure-functions-langgraph`](https://github.com/yeongseon/azure-functions-langgraph-python)
39 changes: 31 additions & 8 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,19 @@ azure-functions-openapi/

This project uses pre-commit to ensure consistent code quality across formatting, linting, typing, and security.

| Tool | Version | Purpose |
|--------|----------|--------------------------------|
| ruff | v0.15.5 | Formatter + linter + import sorter |
| mypy | v1.19.1 | Static type checker |
| bandit | 1.9.4 | Security checker on `src/` only |
There is no Black in this project. Ruff handles both formatting and linting.

| Tool | Purpose |
|--------|------------------------------------|
| ruff | Formatter + linter + import sorter |
| mypy | Static type checker |
| bandit | Security checker on `src/` only |

Pinned versions live in two places and are the source of truth, so this table
deliberately does not repeat them:

- `.pre-commit-config.yaml` — the `rev` of each hook
- `pyproject.toml` — the `dev` optional-dependency pins used by `make` targets

### Bandit Configuration

Expand Down Expand Up @@ -121,22 +129,37 @@ Use these as the **golden commands** for local validation and CI parity. Prefer
| Target | Description |
|--------|-------------|
| `make install` | Create Hatch env and install pre-commit hooks |
| `make format` | Format code (ruff) |
| `make shell` | Open a shell inside the Hatch env |
| `make format` | Format code (ruff format) |
| `make format-check` | Check formatting without writing (ruff format --check) |
| `make style` | Run `ruff check` + `ruff format --check` |
| `make lint` | Run linter (ruff + mypy) |
| `make typecheck` | Run mypy type checking |
| `make security` | Run Bandit security scan |
| `make test` | Run pytest |
| `make cov` | Run tests with coverage |
| `make cov` | Run tests with coverage (gate: `fail_under = 95`) |
| `make e2e-local` | Run e2e tests against local Azurite on `:7071` |
| `make e2e-azure` | Run e2e tests against Azure (`E2E_BASE_URL` required) |
| `make lint-workflows` | Lint release workflows, action pins, and the Hatch matrix |
| `make check` | Run lint + typecheck |
| `make check-all` | Run lint + typecheck + test |
| `make check-all` | Run lint-workflows + check + test + security |
| `make docs` | Build the MkDocs site |
| `make docs-serve` | Serve the docs locally with live reload |
| `make demo` | Run the Swagger UI and example demos |
| `make build` | Build package |
| `make version` | Show the current version |
| `make publish-test` | Publish to TestPyPI |
| `make precommit` | Run all pre-commit hooks |
| `make precommit-install` | Install pre-commit hooks |
| `make doctor` | Show environment diagnostic info |
| `make reset` | Deep clean, then reinstall the env |
| `make hatch-clean` | Remove the Hatch environment |
| `make clean` | Remove build artifacts |
| `make clean-all` | Deep clean (caches, coverage, venv) |
| `make help` | List available targets |

Coverage is enforced at **95%** (`fail_under = 95` in `pyproject.toml`); a drop
below that fails the build.

> For the full release workflow, see [Release Process](release_process.md).

Expand Down
7 changes: 7 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ RUN pip install -r /home/site/wwwroot/requirements.txt
COPY . /home/site/wwwroot
```

`4-python3.12` is just an example: `4` is the Functions runtime major version
and `python3.12` is the interpreter baked into the image. Swap it for whichever
supported interpreter your app targets. This package supports 3.11 through
3.14, and `mcr.microsoft.com/azure-functions/python` publishes `4-python3.11`,
`4-python3.12`, `4-python3.13`, and `4-python3.14`. Pick the tag that matches
the version you test against, and keep it in sync with your CI matrix.

## Upgrading

Upgrade to the latest release:
Expand Down
18 changes: 8 additions & 10 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Testing Guide

This project targets **85%+ total coverage** for core modules.
Latest measured result (CI): **87%** (2026-02-09).
Total coverage is **enforced at 95%**: `fail_under = 95` in `pyproject.toml`
fails the build when the suite drops below it. Run `make cov` for the current
measured number and an HTML report.

## Test Structure

Expand Down Expand Up @@ -57,15 +58,12 @@ hatch run pytest -k "security" -v
- Coverage report is generated as `coverage.xml`.
- Codecov upload runs in CI for the Python 3.11 job.

### Coverage thresholds
### Coverage threshold

| Module | Target |
| --- | --- |
| `decorator.py` | 90%+ |
| `openapi.py` | 85%+ |
| `swagger_ui.py` | 85%+ |
| `cli.py` | 80%+ |
| `utils.py` | 90%+ |
There is one threshold and it applies to the whole package: **95%**, configured
as `fail_under` under `[tool.coverage.report]` in `pyproject.toml`. Per-module
targets are not tracked separately; use `make cov` and the term-missing report
to find uncovered lines.

## Test Categories

Expand Down
4 changes: 2 additions & 2 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,9 @@ spec = generate_openapi_spec(openapi_version=OPENAPI_VERSION_3_2)
Under 3.0/3.1 there is no `query` path-item field, so the operation is dropped
with a warning (and raises under `strict=True`).

### Non-standard HTTP methods (OpenAPI 3.2)
### Non-standard HTTP methods (OpenAPI 3.2)

OpenAPI 3.0/3.1 path items only accept the fixed verb set (`get`, `put`,
OpenAPI 3.0/3.1 path items only accept the fixed verb set (`get`, `put`,
`post`, `delete`, `options`, `head`, `patch`, `trace`). OpenAPI 3.2 adds an
`additionalOperations` map for methods outside that set (for example `PURGE`
or `LINK`). When you document a handler bound to a non-standard method and
Expand Down
2 changes: 1 addition & 1 deletion llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## Package Info

- PyPI: `pip install azure-functions-openapi`
- Version: 0.27.0
- Version: see PyPI (https://pypi.org/project/azure-functions-openapi/) for the current release
- Python: >=3.11, <3.15
- License: MIT
- Docs: https://yeongseon.dev/azure-functions-python/openapi/
Expand Down
2 changes: 1 addition & 1 deletion llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## Package Info

- PyPI: `pip install azure-functions-openapi`
- Version: 0.27.0
- Version: see PyPI (https://pypi.org/project/azure-functions-openapi/) for the current release
- Python: >=3.11, <3.15
- License: MIT
- Docs: https://yeongseon.dev/azure-functions-python/openapi/
Expand Down
Loading