* [Buildroot] [PATCH] package/python-servestatic: new package
@ 2026-09-07 6:08 Sebastian Michel
2026-10-03 17:34 ` Thomas Petazzoni via buildroot
0 siblings, 1 reply; 2+ messages in thread
From: Sebastian Michel @ 2026-09-07 6:08 UTC (permalink / raw)
To: buildroot; +Cc: James Hilliard, Thomas Petazzoni, Sebastian Michel
Added package for ServeStatic, version 4.3.2.
https://github.com/Archmonger/ServeStatic
Added a runtime test that verifies static-file responses through both
the WSGI and ASGI interfaces. Also verified that the installed
servestatic command-line entry point starts successfully.
Signed-off-by: Sebastian Michel <sebastian.michel@oss.othermo.de>
---
DEVELOPERS | 5 +
package/Config.in | 1 +
package/python-servestatic/Config.in | 11 ++
.../python-servestatic.hash | 3 +
.../python-servestatic/python-servestatic.mk | 13 ++
.../package/sample_python_servestatic.py | 118 ++++++++++++++++++
.../tests/package/test_python_servestatic.py | 19 +++
7 files changed, 170 insertions(+)
create mode 100644 package/python-servestatic/Config.in
create mode 100644 package/python-servestatic/python-servestatic.hash
create mode 100644 package/python-servestatic/python-servestatic.mk
create mode 100644 support/testing/tests/package/sample_python_servestatic.py
create mode 100644 support/testing/tests/package/test_python_servestatic.py
diff --git a/DEVELOPERS b/DEVELOPERS
index 53104cc60b..4e3dfb370c 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -3001,6 +3001,11 @@ F: package/lrzip/
N: Sam Voss <sam.voss@gmail.com>
F: package/ripgrep/
+N: Sebastian Michel <sebastian.michel@oss.othermo.de>
+F: package/python-servestatic/
+F: support/testing/tests/package/sample_python_servestatic.py
+F: support/testing/tests/package/test_python_servestatic.py
+
N: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
F: board/armadeus/
F: configs/armadeus*
diff --git a/package/Config.in b/package/Config.in
index 6058800682..79871aefd4 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -1418,6 +1418,7 @@ menu "External python modules"
source "package/python-sentry-sdk/Config.in"
source "package/python-serial/Config.in"
source "package/python-serial-asyncio/Config.in"
+ source "package/python-servestatic/Config.in"
source "package/python-service-identity/Config.in"
source "package/python-setproctitle/Config.in"
source "package/python-setuptools/Config.in"
diff --git a/package/python-servestatic/Config.in b/package/python-servestatic/Config.in
new file mode 100644
index 0000000000..b2a1e2a45d
--- /dev/null
+++ b/package/python-servestatic/Config.in
@@ -0,0 +1,11 @@
+config BR2_PACKAGE_PYTHON_SERVESTATIC
+ bool "python-servestatic"
+ select BR2_PACKAGE_PYTHON_ASGIREF # runtime dependency
+ select BR2_PACKAGE_PYTHON3_ZLIB # runtime dependency for cli / servestatic.storage usage
+ help
+ Production-grade static file server for Python WSGI and ASGI.
+
+ ServeStatic runs standalone or as middleware for an existing
+ WSGI, ASGI, or Django application.
+
+ https://github.com/Archmonger/ServeStatic
diff --git a/package/python-servestatic/python-servestatic.hash b/package/python-servestatic/python-servestatic.hash
new file mode 100644
index 0000000000..6d1fb6ecf9
--- /dev/null
+++ b/package/python-servestatic/python-servestatic.hash
@@ -0,0 +1,3 @@
+# Locally computed sha256 checksums
+sha256 1ab67d0654910c000864f9b6d7fefa8befc21a2156d539cf9e519afcc27c4d63 python-servestatic-4.3.2.tar.gz
+sha256 1770e2fc440cce75b2b2bd1580c6d59f58a497f0bb7abe91a0136bee0f688bf3 LICENSE.md
diff --git a/package/python-servestatic/python-servestatic.mk b/package/python-servestatic/python-servestatic.mk
new file mode 100644
index 0000000000..26d93fe9b5
--- /dev/null
+++ b/package/python-servestatic/python-servestatic.mk
@@ -0,0 +1,13 @@
+################################################################################
+#
+# python-servestatic
+#
+################################################################################
+
+PYTHON_SERVESTATIC_VERSION = 4.3.2
+PYTHON_SERVESTATIC_SITE = $(call github,Archmonger,ServeStatic,$(PYTHON_SERVESTATIC_VERSION))
+PYTHON_SERVESTATIC_SETUP_TYPE = hatch
+PYTHON_SERVESTATIC_LICENSE = MIT
+PYTHON_SERVESTATIC_LICENSE_FILES = LICENSE.md
+
+$(eval $(python-package))
diff --git a/support/testing/tests/package/sample_python_servestatic.py b/support/testing/tests/package/sample_python_servestatic.py
new file mode 100644
index 0000000000..22c69cdbcf
--- /dev/null
+++ b/support/testing/tests/package/sample_python_servestatic.py
@@ -0,0 +1,118 @@
+import asyncio
+import os
+import tempfile
+from collections.abc import Callable
+from types import TracebackType
+from typing import TypeAlias
+from wsgiref.types import StartResponse
+
+from asgiref.typing import HTTPScope, HTTPRequestEvent, ASGIVersions
+
+from servestatic import ServeStatic, ServeStaticASGI
+
+CONTENT = b"ServeStatic works on Buildroot.\n"
+
+_ExcInfo: TypeAlias = tuple[type[BaseException], BaseException, TracebackType]
+_OptExcInfo: TypeAlias = _ExcInfo | tuple[None, None, None]
+
+
+def assert_response_ok(status, headers, body):
+ assert status == 200
+ assert headers["content-length"] == str(len(CONTENT))
+ assert headers["content-type"].startswith("text/plain")
+ assert body == CONTENT
+
+
+def test_wsgi(content_directory):
+ app = ServeStatic(None, root=content_directory)
+ response_data = {}
+
+ class DummyStartResponse(StartResponse):
+ def __call__(self, status: str, headers: list[tuple[str, str]], exc_info: _OptExcInfo | None = None, /) -> \
+ Callable[[bytes], object]:
+ response_data["status"] = int(status.split()[0])
+ response_data["headers"] = {
+ key.lower(): value for key, value in headers
+ }
+ return super().__call__(status, headers, exc_info)
+
+ start_response = DummyStartResponse()
+
+ environ_test_request = {
+ "PATH_INFO": "/test_content.txt",
+ "REQUEST_METHOD": "GET",
+ }
+ response = app(environ_test_request, start_response)
+ try:
+ body = b"".join(response)
+ finally:
+ close = getattr(response, "close", None)
+ if callable(close):
+ close: Callable[None]
+ close()
+
+ assert_response_ok(
+ response_data["status"], response_data["headers"], body
+ )
+
+
+async def test_asgi(content_directory):
+ app = ServeStaticASGI(None, root=content_directory)
+ messages_received_from_application = []
+
+ async def receive() -> HTTPRequestEvent:
+ return HTTPRequestEvent(
+ type="http.request",
+ body=b"",
+ more_body=False,
+ )
+
+ # will be invoked when the application "sends" data back -> append all sent data to the messages list
+ async def send(message):
+ messages_received_from_application.append(message)
+
+ # run the test request
+ scope_test_request = HTTPScope(
+ type="http",
+ asgi=ASGIVersions(
+ version="3.0",
+ spec_version="2.5"
+ ),
+ http_version="1.1",
+ method="GET",
+ scheme="http",
+ path="/test_content.txt",
+ raw_path=b"/hello.txt",
+ query_string=b"",
+ root_path="",
+ headers=[],
+ client=("127.0.0.1", 12345),
+ server=("127.0.0.1", 80),
+ extensions=None
+ )
+ await app(scope_test_request, receive, send)
+
+ # first segment contains the headers
+ message_with_headers = messages_received_from_application[0]
+
+ # convert headers into correct form for assert_response_ok
+ headers = {
+ key.decode(): value.decode() for key, value in message_with_headers["headers"]
+ }
+
+ # collect content of all "body" type messages
+ body = b"".join(
+ message.get("body", b"")
+ for message in messages_received_from_application
+ if message["type"] == "http.response.body"
+ )
+
+ # assert everything works as expected
+ assert_response_ok(message_with_headers["status"], headers, body)
+
+
+with tempfile.TemporaryDirectory() as tmp_content_directory:
+ with open(os.path.join(tmp_content_directory, "test_content.txt"), "wb") as static_file:
+ static_file.write(CONTENT)
+ test_wsgi(tmp_content_directory)
+ asyncio.run(test_asgi(tmp_content_directory))
diff --git a/support/testing/tests/package/test_python_servestatic.py b/support/testing/tests/package/test_python_servestatic.py
new file mode 100644
index 0000000000..d9c762962a
--- /dev/null
+++ b/support/testing/tests/package/test_python_servestatic.py
@@ -0,0 +1,19 @@
+from tests.package.test_python import TestPythonPackageBase
+
+
+class TestPythonServeStatic(TestPythonPackageBase):
+ __test__ = True
+ config = TestPythonPackageBase.config + \
+ """
+ BR2_PACKAGE_PYTHON3=y
+ BR2_PACKAGE_PYTHON_SERVESTATIC=y
+ """
+
+ sample_scripts = ["tests/package/sample_python_servestatic.py"]
+
+ def run_sample_scripts(self):
+ self.assertRunOk(
+ "servestatic --help | grep -q 'Process static files'"
+ )
+
+ super().run_sample_scripts()
--
2.55.0
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [Buildroot] [PATCH] package/python-servestatic: new package
2026-09-07 6:08 [Buildroot] [PATCH] package/python-servestatic: new package Sebastian Michel
@ 2026-10-03 17:34 ` Thomas Petazzoni via buildroot
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Petazzoni via buildroot @ 2026-10-03 17:34 UTC (permalink / raw)
To: Sebastian Michel; +Cc: buildroot, James Hilliard
On Mon, Sep 07, 2026 at 08:08:10AM +0200, Sebastian Michel wrote:
> Added package for ServeStatic, version 4.3.2.
> https://github.com/Archmonger/ServeStatic
>
> Added a runtime test that verifies static-file responses through both
> the WSGI and ASGI interfaces. Also verified that the installed
> servestatic command-line entry point starts successfully.
>
> Signed-off-by: Sebastian Michel <sebastian.michel@oss.othermo.de>
Applied to master, thanks!
Best regards,
Thomas Petazzoni
--
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-03 17:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 6:08 [Buildroot] [PATCH] package/python-servestatic: new package Sebastian Michel
2026-10-03 17:34 ` Thomas Petazzoni via buildroot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.