From 33e8582079e03d8b4e8ee2c1cb4b42bcc82d729a Mon Sep 17 00:00:00 2001 From: gitea-actions Date: Sat, 22 Aug 2026 18:29:00 +0200 Subject: [PATCH] =?UTF-8?q?Obsluhovat=20to=20waitressem,=20ne=20v=C3=BDvoj?= =?UTF-8?q?ov=C3=BDm=20serverem=20Flasku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flask pod pěkně naformátovanou úvodní hlášku vysypal červené varování, že tohle není produkční server. Waitress je čistě pythonní, takže ho PyInstaller zabalí bez řečí, a osm vláken pobere telefony u stolu i tabuli, která se doptává každé dvě vteřiny. Cestou se ukázalo, že hláška se nikdy nedostala do přesměrovaného výstupu: mimo konzoli drží Python výstup v bloku a pouští ho, až program skončí — jenže server neskončí. Zkouška binárky u Gitey si logovala do souboru a pak ho vypisovala, takže celou dobu tiskla prázdno. Řeší to řádkové bufferování v console.utf8(), kam to patří vedle té kódové stránky. --- README.md | 4 ++++ console.py | 13 ++++++++++--- tests/test_console.py | 19 ++++++++++++++++++- web.py | 8 +++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ec6eacd..05eb5eb 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,10 @@ schématu ještě nepsala, se poznají podle nuly a orazítkují se. Databázi založenou novější verzí počitadla appka odmítne otevřít, místo aby ji tiše rozbila. +Obsluhuje to `waitress` — čistě pythonní WSGI server, který se zabalí do +binárky stejně snadno jako zbytek. Vestavěný server Flasku by pod úvodní +hlášku vysypal varování, že takhle se to nemá, a měl by pravdu. + Počítá se s domácí sítí — appka nemá přihlašování a kdokoli na stejné WiFi může zapisovat. diff --git a/console.py b/console.py index cf6a35d..3ab13ab 100644 --- a/console.py +++ b/console.py @@ -1,10 +1,10 @@ -"""Aby čeština prošla i tam, kde konzole čeká něco jiného.""" +"""Aby výstup prošel i tam, kde ho nikdo nečeká na konzoli.""" import sys def utf8() -> None: - """Přepne standardní výstup na UTF-8. + """Přepne standardní výstup na UTF-8 a na řádkové bufferování. Windows sahá po historické kódové stránce (cp1252, cp852) všude, kde výstup není konzole — přesměrovaný do souboru, puštěný ze skriptu, ve @@ -14,7 +14,14 @@ def utf8() -> None: Na konzoli i na ostatních systémech je UTF-8 dávno výchozí a tohle je tam prázdná operace. `errors="replace"` je pojistka pro zbylé případy: rozsypaný háček je pořád lepší než spadlý server. + + Řádkové bufferování řeší druhou půlku téhož problému. Mimo konzoli + Python drží výstup v bloku a pouští ho, až se naplní nebo až program + skončí — jenže server neskončí, ten běží. Kdo si ho pustí na pozadí + s výpisem do souboru, našel by tam prázdno; přesně to dělá zkouška + binárky v CI. Pár řádek hlášky za to bufferovat nemá cenu. """ for stream in (sys.stdout, sys.stderr): if hasattr(stream, "reconfigure"): - stream.reconfigure(encoding="utf-8", errors="replace") + stream.reconfigure(encoding="utf-8", errors="replace", + line_buffering=True) diff --git a/tests/test_console.py b/tests/test_console.py index f2fed1b..9c7fed2 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -9,10 +9,12 @@ class Proud: def __init__(self): self.encoding = "cp1252" self.errors = "strict" + self.line_buffering = False - def reconfigure(self, encoding, errors): + def reconfigure(self, encoding, errors, line_buffering=False): self.encoding = encoding self.errors = errors + self.line_buffering = line_buffering def test_vystup_se_prepne_na_utf8(monkeypatch): @@ -24,6 +26,7 @@ def test_vystup_se_prepne_na_utf8(monkeypatch): assert (out.encoding, out.errors) == ("utf-8", "replace") assert (err.encoding, err.errors) == ("utf-8", "replace") + assert out.line_buffering and err.line_buffering def test_cestina_projde_i_pres_cp1252(monkeypatch): @@ -46,3 +49,17 @@ def test_proud_bez_reconfigure_se_prezije(monkeypatch): monkeypatch.setattr(console.sys, "stderr", object()) console.utf8() + + +def test_hlaska_je_v_souboru_hned(tmp_path, monkeypatch): + """Server běží dál, takže na vyprázdnění bufferu při konci se čekat nedá.""" + cesta = tmp_path / "server.log" + with cesta.open("w", encoding="utf-8") as soubor: + monkeypatch.setattr(console.sys, "stdout", soubor) + monkeypatch.setattr(console.sys, "stderr", soubor) + + console.utf8() + print("Počitadlo je dostupné na:", file=console.sys.stdout) + + # Bez zavření souboru — přesně jako u běžícího serveru. + assert "Počitadlo je dostupné" in cesta.read_text(encoding="utf-8") diff --git a/web.py b/web.py index 53767e5..1e96c0c 100644 --- a/web.py +++ b/web.py @@ -17,6 +17,7 @@ import qrcode from flask import (Flask, abort, g, redirect, render_template, request, url_for) from markupsafe import Markup, escape +from waitress import serve import console import net @@ -353,4 +354,9 @@ if __name__ == "__main__": sys.exit(0) announce() - app.run(host="0.0.0.0", port=PORT, threaded=True) + + # Ne vestavěný server Flasku: ten pod úvodní hlášku vysype červené + # varování, že takhle se to nemá, a má pravdu. Waitress je čistě + # pythonní, takže se zabalí do binárky bez řečí, a osm vláken pobere + # telefony u stolu i tabuli, která se doptává každé dvě vteřiny. + serve(app, host="0.0.0.0", port=PORT, threads=8)