Migration Guide: 0.5.0 → 0.6.0¶
Status: Released. This guide covers upgrading from 0.5.0 to the 0.6.x line and documents every breaking change introduced by PRs #81-#94, so 0.5.0 users can upgrade with a single read. If you are already on any 0.6.x release, no further migration is required — this guide is retained as a historical reference for the 0.5.0 → 0.6.0 jump.
0.6.0 is a hardening release. It tightens default security posture, fixes a packaging mismatch that prevented install via the documented command, and ships several CLI quality-of-life improvements. There are several breaking changes; all are documented below with migration steps.
TL;DR¶
| Change | Impact | Action |
|---|---|---|
PyPI package renamed: azure-functions-scaffold-python → azure-functions-scaffold |
Old install command stops working (returns 404) | pip install azure-functions-scaffold |
Sibling deps in generated pyproject.toml lose -python suffix |
New scaffolds only; existing projects unaffected | None for existing projects |
Default auth_level flipped from ANONYMOUS to FUNCTION for business endpoints |
New scaffolds expose endpoints requiring function key | Set keys, or downgrade explicitly per-route |
Webhook handlers fail closed without WEBHOOK_SECRET |
New scaffolds 503 until secret is configured | Add WEBHOOK_SECRET to local.settings.json and app settings |
function_app.py marker comments renamed |
Existing scaffolds keep working via legacy-marker shim | Optional: update marker comment for cleanliness |
| Identifier validation rejects Python keywords / invalid identifiers | afs api add if etc. now errors out instead of generating broken code |
Pick a valid Python identifier |
--overwrite requires TTY confirmation or explicit --yes |
Scripted use of --overwrite without --yes now blocks |
Add --yes to non-interactive invocations |
azure-functions-scaffold-python long-form CLI entry removed |
Use afs short form, or azure-functions-scaffold long form |
s/azure-functions-scaffold-python/afs/g in your scripts |
add and profiles commands replaced; deprecation shims forward |
Shims emit a deprecation warning | Migrate to the modern command names listed by the warning |
If you only do one thing: re-install with the new name and re-read your generated local.settings.json.example.
1. Packaging rename (PR #90)¶
What changed¶
pyproject.toml[project].nameis nowazure-functions-scaffold(wasazure-functions-scaffold-python).- The wheel filename is now
azure_functions_scaffold-0.6.0-py3-none-any.whl(wasazure_functions_scaffold_python-…). - The long-form CLI entry point is now
azure-functions-scaffold(wasazure-functions-scaffold-python). The short aliasafsis unchanged. - Every generated project's
pyproject.tomlnow depends on the unsuffixed sibling packages:azure-functions-logging,azure-functions-openapi,azure-functions-validation,azure-functions-doctor,azure-functions-db. The-python-suffixed names were never published on PyPI and would 404. - Marker comments in generated
function_app.pyare now# azure-functions-scaffold: …(was# azure-functions-scaffold-python: …). The generator recognizes both legacy and new markers — see §5.
Why¶
The PyPI package azure-functions-scaffold-python does not exist. The package owner published azure-functions-scaffold v0.5.0. Anyone following 0.5.0's pip install azure-functions-scaffold-python instruction got a 404. Same problem for every sibling reference.
Migration¶
# Old (does not work)
pip install azure-functions-scaffold-python
# New
pip install azure-functions-scaffold
If your scripts invoke azure-functions-scaffold-python as a CLI long-form, switch to afs (preferred) or azure-functions-scaffold:
# Old
azure-functions-scaffold-python new my-api
# New
afs new my-api
# or
azure-functions-scaffold new my-api
For existing scaffolded projects: no action required. The -python-suffixed dep names were never resolvable, so your pip install -e . was already failing or pinned to local copies. Update the dep names in your project's pyproject.toml when convenient:
# Old
dependencies = [
"azure-functions-logging-python>=0.5.0",
"azure-functions-openapi-python>=0.17.0",
]
# New
dependencies = [
"azure-functions-logging>=0.5.0",
"azure-functions-openapi>=0.17.0",
]
The GitHub repository name (azure-functions-scaffold-python) and docs URL are unchanged; only the PyPI package name is unsuffixed.
2. Secure default auth (PR #83)¶
What changed¶
- All business-endpoint templates now default to
func.AuthLevel.FUNCTION(wasANONYMOUS). - The webhook handler refuses to start without
WEBHOOK_SECRET. Missing secret produces an HTTP 503 and aRuntimeErrorin logs. local.settings.json.exampleships with aWEBHOOK_SECRETplaceholder.
The only endpoints that remain ANONYMOUS are the OpenAPI spec / Swagger UI surfaces (/api/openapi.json, /api/openapi.yaml, /api/docs) and the /api/health endpoint, which are intentionally public.
Why¶
Generating a project that exposes business endpoints with auth_level=ANONYMOUS is a security regression by default. Most Azure Functions deployments are public-internet-facing. Anonymous business endpoints are almost always wrong; users can opt out per-endpoint when they actually want anonymous (e.g., public webhooks with HMAC verification done in-handler).
Migration¶
For new scaffolds: add a function key in the Azure Portal or local.settings.json, and pass it as ?code=<key> or x-functions-key: <key> when calling the endpoint.
For existing scaffolds that you regenerate with 0.6.0 overlays: review every blueprint route. If you genuinely want ANONYMOUS, set it explicitly:
@app.route(route="public-endpoint", auth_level=func.AuthLevel.ANONYMOUS)
def public_endpoint(req): ...
For webhook endpoints, the new fail-closed behavior requires:
In production, set WEBHOOK_SECRET as an app setting in the Function App configuration. Without it, the endpoint returns 503 instead of silently accepting unverified payloads.
3. Marker comment rename (PR #81 + PR #90)¶
What changed¶
function_app.py marker comments used by afs api add, afs api add-route, afs api add-resource, and afs advanced add are now:
Was:
# azure-functions-scaffold-python: function imports
# azure-functions-scaffold-python: function registrations
Why¶
Aligns with the unsuffixed package name. A separate fix in PR #81 first caught a long-standing drift between the generator's marker constants and the templates' actual comments — the markers had silently been broken in production while unit tests stayed green.
Migration¶
The generator recognizes BOTH the new marker and the legacy azure-functions-scaffold-python: marker. Existing scaffolds continue to work without change. afs api add and friends find either marker and insert near it.
If you want the cosmetic update for new-installs consistency:
# In your scaffolded project's function_app.py
sed -i 's/# azure-functions-scaffold-python: /# azure-functions-scaffold: /g' function_app.py
4. Identifier validation (PR #82)¶
What changed¶
afs api add, afs api add-route, afs api add-resource, afs advanced add, and project-creation commands now reject:
- Python hard keywords (
if,class,return, …) - Soft keywords (
match,case,type, …) - Strings that aren't valid Python identifiers (
123foo,my-route, …)
Previously these would silently generate broken code that failed at import time.
Why¶
afs api add if produced a file app/functions/if.py containing def if(req): … — a SyntaxError. Better to error early with a clear message.
Migration¶
Use a valid Python identifier. If you previously got away with naming a function after a keyword, rename it. Example error:
Error: 'if' is a Python keyword and cannot be used as a function name.
Pick a name that is a valid Python identifier (e.g., 'check_if').
5. --overwrite safety guard (PR #89)¶
What changed¶
When afs new / afs api new / afs advanced new is invoked with --overwrite against a non-empty target directory, the CLI:
- Refuses if the target contains a
.git/directory. - Prompts for
y/Nconfirmation if stdin is a TTY. - Refuses with a non-zero exit if stdin is not a TTY and
--yeswas not provided.
A new --yes / -y flag short-circuits the prompt for scripted use.
Why¶
--overwrite against a populated directory was a footgun. Deleting a developer's git repo by typo is unacceptable.
Migration¶
For scripted / CI use, add --yes (or -y):
For interactive use, no change — you'll be prompted.
If the target directory is a git repo, you must remove it manually first; --overwrite will refuse to delete it under any flag.
6. Python 3.14 Preview status (PR #91)¶
What changed¶
Selecting --python-version 3.14 now emits a yellow stderr warning informing you that 3.14 is Preview on Azure Functions today, with limited regional / plan / Flex Consumption support.
3.14 is still accepted; the warning is informational only.
Why¶
Azure Functions' GA support for Python 3.14 is incomplete at the time of this writing. Users picking 3.14 today routinely hit deployment surprises.
Migration¶
None required. If you want to silence the warning for a CI lane, redirect stderr or downgrade the chosen version:
The recommended default in Quick Start examples is now 3.12.
7. CLI ergonomic changes¶
afs with no subcommand prints help (PR #86)¶
Was: silent / undefined. Now: afs --help is printed.
afs add / afs profiles are deprecation shims (PR #87)¶
These commands still work but print a one-time stderr deprecation warning pointing to the modern command name. They will be removed in a future major release.
Migrate to:
- afs add → afs api add (or the appropriate intent group)
- afs profiles → afs presets
Flag/template compatibility validation (PR #88)¶
afs advanced new rejects invalid feature-flag combinations before generating any files. Example: --with-openapi against the langgraph template errors out cleanly instead of producing a half-generated project.
Atomic generation (PR #85)¶
afs api add, afs advanced add, afs api add-resource, and afs api add-route now use a two-phase commit internally. If any step fails (e.g., disk full mid-write), no partial files are left behind. Rollback is automatic.
ADDABLE_TRIGGERS split (PR #84)¶
The CLI's --trigger help string now correctly lists only the triggers that afs … add can extend an existing project with, separately from the broader set of triggers used at scaffold time.
8. Generated project quality (PR #93)¶
What changed¶
Every generated project's pyproject.toml now includes:
Why¶
Without pythonpath = ["."], pytest 8+ fails at collection time:
This was broken in every template in 0.5.0. The new generated-project smoke E2E workflow (PR #94) now catches this class of bug in CI.
Migration¶
For existing scaffolds: edit your project's pyproject.toml:
Or run pytest with PYTHONPATH=.:
9. CI infrastructure (PR #94)¶
A new workflow templates-smoke.yml scaffolds every template on every PR that touches src/azure_functions_scaffold/templates/** and runs the generated project's own compileall, ruff, mypy, and pytest. This is internal infrastructure — no migration impact for users — but it is the reason §2, §6, and §8 surfaced as fixes in this release.
Verification checklist¶
After upgrading:
- [ ]
pip install azure-functions-scaffoldsucceeds (use the new name). - [ ]
afs --versionprints a0.6.xversion (e.g.0.6.1). - [ ] If you use webhooks,
WEBHOOK_SECRETis configured inlocal.settings.jsonand Azure app settings. - [ ] Existing scaffolded projects still respond to
afs api addetc. (legacy marker shim). - [ ] Scripted
--overwriteinvocations include--yes. - [ ] Generated
pyproject.tomlhaspythonpath = ["."](re-runafs api add pingor just edit manually for old scaffolds). - [ ] You aren't pinning
--python-version 3.14in production unless you've verified Preview support for your region/plan.
Reporting issues¶
If you hit something this guide didn't cover, open an issue at https://github.com/yeongseon/azure-functions-scaffold-python/issues with the label 0.6.0-migration.