Repository navigation
Releases: offerrall/FuncToWeb
Release list
2.7.6
2.7.5
2.7.4
Changed
- Documentation only: the README becomes a short entrance to the documentation
site at https://offerrall.github.io/func-to-web/, anddocs/overview.mdholds
the introduction and its fuller examples (the API,/doc, FastAPI,sdk.js,
how it works, the CRUD,OpenForm, files, streaming, capabilities and the
comparison). The design notes are listed as maintainer pages. - The layers and
pytypehintstoreare described once, in
docs/architecture.md, and the widget demo once, indocs/types.md; the
hand-kept line and example counts, the dependency tree, the badges, the
install commands and the Status and License sections are gone, since the
site derives them. docs/examples.mdlists theusers.py,bookings.pyandgallery.py
mini-apps, and states once which examples need an extra library.- The design notes state the theme and the stream polling as facts rather than
plans, therun()banner sample no longer carries a stale version, and links
to pytypehint, pytypehintweb and pytypehintstore point to their documentation
sites. - The changelog headings use one format, and seven dates are corrected to the
PyPI upload dates (0.1.0, 0.4.4, 0.5.0, 0.9.8, 1.0.1, 2.5.0 and 2.6.1). pyproject.tomlgains the Documentation URL, and Source is renamed
Repository.
The code is the same as 2.7.3.
2.7.3
2.7.2
Changed
- Documentation only: the documentation index moves from
docs/index.mdinto
the README's Documentation section, and the README no longer repeats the
version in its title and status line. The code is the same as 2.7.1. - The READMEs inside
examples/become one page,docs/examples.md, listed
with the rest of the documentation.
Fixed
- The test suite runs again with anyio 4.15, whose deprecation of
anyio.abc.BlockingPortalis raised inside Starlette'sTestClient; that one
warning is ignored, every other warning is still an error.
2.7.1
[2.7.1] - 2026-09-24
Fixed
openModal()no longer opens at full height and then shrinks. With
autoHeightthe panel stays invisible until the page reports its height;
the overlay appears at once. If no height arrives within 1.5 s the panel is
shown anyway.autoHeight: falseis unchanged.
2.6.2
[2.6.2] - 2026-09-13
Added
- Per-opening
hide_submitfor Pythonpage_of()and HTTP function pages,
exposed ashideSubmitin SDKpageUrl(),embed()andopenModal().
Hides the Submit button without reserving space or enabling autorun.
The default remains false. Combine withautorunfor result-only previews;
existing validation, uploads and result rendering remain in use.
2.6.1
[2.6.1] - 2026-09-13
FuncToWeb 2.6.1 is stable, used daily and actively maintained.
Added
- Automatic content height for
embed()andopenModal(), including growth
and shrinkage after form edits and results. Modal height remains bounded by
the configured height and viewport.autoHeight: falsekeeps fixed sizing. - Per-opening
hide_titleandhide_descriptionoptions for function pages,
available through the URL andpage_of(). The SDK exposes them ashideTitle
andhideDescriptioninpageUrl(),embed()andopenModal(). Hiding both
removes the visible header and its spacing.
Fixed
- An overlong file reference in
prefillnow returns400when the filesystem
rejects its name during the existence check, instead of an internal500.
Existing stored names remain readable beyond the upload reference limit.
2.6.0
[2.6.0] - 2026-08-13
FuncToWeb moves onto pytypehintweb 1.1.0, and with it onto pytypehint 1.0.0.
The annotation that marks a file parameter is now FileHint, and the division of
labour around files is redrawn: the core stopped touching the filesystem, so
everything that was a promise about the real file on disk — that it exists,
that it is a file and not a directory, that its bytes fall between min_size and
max_size — is now stated only where it is actually enforced. For FuncToWeb that
is its own storage layer, which already did that work; nothing about uploads,
references or the pending/promoted lifecycle is weaker than it was in 2.5.0.
Changed
- Breaking:
IsPathFileis replaced byFileHint, re-exported from
func_to_webwith the same three fields (extensions,min_size,
max_size). This is a clean cut: there is no alias, no deprecation warning and
no support forpytypehint 0.x. Rename the import and the call —
Annotated[str, IsPathFile(extensions=(".png",))]becomes
Annotated[str, FileHint(extensions=(".png",))]— and nothing else changes. - Breaking (behaviour):
Signature.build()no longer checks that a file
value exists, that it is a file, or how large it is. In 2.5.0 an invocation
carrying a path to a missing, oversized or undersized file was refused by the
layer below; in 2.6.0 the core only checks the extension of the value it is
given, and builds the arguments. - Breaking (behaviour):
FileHint.min_size/FileHint.max_sizeno longer
have a server-side second check during invocation. The browser applies them to
a file it has just picked, because there it holds the bytes and knows
file.size; a stored reference carries no bytes, the browser cannot weigh it
and the core no longer stats it. Do not expect a422from/invokefor byte
bounds on a reference. An application that needs an authoritative guarantee
about stored content owns that policy itself — FuncToWeb does not invent one
silently, andmax_upload_bytesremains the endpoint policy it always was. - A file default written by the author as a server path is still refused unless
it belongs to the storage directory, and is still published as a reference and
never as a path. What changed is only what backs it: in 2.5.0 the core also
refused a default that did not exist, so a stale default failed at build time.
In 2.6.0 that default becomes a reference, and the resolver refuses it at
invocation instead, when it fails to resolve.
Fixed
OpenFormnow forwards a union-valued prefill in the same transport a browser
submit sends, so an opening whose target has a parameter of two or more union
branches works. It answered400before, in every version that had the
feature: the opening published the plan's own way of writing a default —
{"branch": …, "value": …}, which names the control the page opens on — and
the destination reads a prefill as a submit, where a branch is named by the
value itself or not at all. Depending on the union the answer was
expected int | str, got dictorambiguous value: wrap it as $type. The
conversion is the plan's own answer rather than a rule restated in FuncToWeb:
each branch already carries the modepytypehintwebchose for it, and the
three modes emit whatform.jsemits — bare forplain,
{"$type": …, "$value": …}forwrapped,{"$type": …, …fields}for
inline.X | Nonewas never affected and is unchanged: one real branch
compiles no choice at all, so the two spellings already agreed.
Unchanged, and now the only thing that says so
- Reference syntax, separators,
.., control characters, reserved names and
markers, and length limits stay insegment_of()/stored_of(). - Confinement to the uploads directory, in both directions:
stored_of()
requires the resolved parent to be the storage root, andreference_of()
refuses a path whose round trip through storage does not land back on itself,
which is what keeps a symbolic link from escaping. - Existence.
stored_file()promotes a pending upload or raises
FileNotFoundError, so a reference that does not resolve never reaches the
function./invokeanswers422;/invoke-streamanswers200and carries
the same error in itsresultevent, as it does for every rejection once the
stream is open. Either way the call is not made, and that refusal is a
FuncToWeb storage rule — after 2.6.0, the only one on this path. max_upload_bytesis authoritative and unchanged: it may reject early on
Content-Length, but it never trusts it alone — the bytes are counted as they
arrive, the transfer is cut the moment the limit is passed, the partial file is
deleted and the answer is413.- The pending/promoted lifecycle, the sweeper, expiry and the reuse of a promoted
reference without a second upload. OpenFormstill hands a file on to the next function as a reference, hidden
and not re-uploaded; the local path never travels.
Dependencies
pytypehintweb==0.0.5→pytypehintweb==1.1.0, which bringspytypehint 1.0.0transitively. FuncToWeb still declares no direct dependency on
pytypehint: it arrives throughpytypehintweb, as it has since 2.3.0.- 1.1.0 delegates the portable decoding to the core inside its own
decode():
it callsschema.decode()and then walks the decoded tree applying the
file_resolverto each file node. The simplification happens in
pytypehintweb; FuncToWeb implements none of it and its call sites are
unchanged. - The mypy exception
untyped_calls_exclude = ["pytypehintweb"]is removed:
1.1.0 annotatesdecode(), so the package passes strict again with no
exemption. starlette==0.49.3anduvicorn==0.38.0are unchanged.
2.5.0
[2.5.0] - 2026-08-08
FuncToWeb now depends directly on Starlette instead of FastAPI. app_of()
returns a mountable Starlette/ASGI application, and run() serves that same
application with Uvicorn. FastAPI remains a naturally compatible host through
app.mount(...), but is no longer a runtime dependency. There is no 2.4.0: the
numbering goes from 2.3.0 straight to 2.5.0.
Changed
- Breaking:
router_of()is replaced byapp_of()and
include_router(..., prefix=...)becomesmount(prefix, app_of(...)). - Breaking:
fastapi_kwargsis removed fromrun();uvicorn_kwargs
remains unchanged. - Breaking: the per-router dependencies of
include_router(..., dependencies=[Depends(...)])have nowhere to go, because
a mount is an application inside another and not a router:mount()takes no
dependenciesand raisesTypeErrorfor it. A host that authenticated the
space that way applies the same check as middleware around the mount, wrapping
app_of(...)before mounting it. Dropping the argument to get past the
TypeErrorleaves the space mounted and unauthenticated. - A
POSTcarryingContent-Type: text/plainwith a valid JSON body now
answers200. FastAPI read the declared content type first and took the body
for a string, which was a422; the body is parsed as JSON whatever the
header says. - A route that answers
GETnow answersHEADas well, which is the behaviour
ofstarlette.routing.Route; with FastAPI's own routerHEADwas a405. - Invalid or non-object JSON keeps status
422but now uses a small
FuncToWeb transport error instead of FastAPI/Pydantic's validation payload. - The application index at
/is part ofapp_of()as well as standalone
run().
Dependencies
- Replaced
fastapi==0.121.1withstarlette==0.49.3at runtime. - FastAPI is retained only in the test extra to verify host compatibility.