* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox