Python unbuffered print v cmd

Python unbuffered print v cmd
« kdy: 18. 01. 2022, 15:33:18 »
Po přenesení jednoho python programu z linuxu pod windows jsem zjistil divné chování příkazu print.
Aby se mi ve výstupech z programů (kdy se spojuje stout a stderr) nemíchalo
pořadí informací, zvykl jsem si nastavit python pomocí -u aby nebufferoval výstupy.

Když tento program spustím ve windows příkazové řádce
nedočkám správného konce výstupu - slova "konec":
#!/usr/bin/python3 -u
TXT = ""
for I in range(2000):
   TXT += f"{I:09d}\n"
TXT += "konec"
print(TXT)

Výstup skončí cca u hodnoty 1000.

Pokud na 1. řádku odstraním -u, začne se program
chovat správně, poslední slovo je 'konec'.
Popisované chování je stejné i když je na prvním řádku správnější:
#!python3 -u

Děje se tak jen pokud jde výstup přímo do terminálu a je nastaven zákaz bufferovaní.
Pokud jde výstup do souboru, nebo pokud odstraním '-u', funguje to správně.

Řešením asi bude vypínat bufferování až v programu, v závislosti na platformě:
if os.name == "posix":
   import io
   sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
   sys.stderr = io.TextIOWrapper(open(sys.stderr.fileno(), 'wb', 0), write_through=True)


Re:Python unbuffered print v cmd
« Odpověď #1 kdy: 18. 01. 2022, 15:55:19 »
píšeš o windowsu, ale spouštíš bash, přes co ho máš? cygwin? WSL?

Můžeš zkusit variantu s print("", flush=True)? Mám pocit, že to -u se ti správně nepřepíše, myslím, že by bylo vhodnější použít #!/usr/bin/env -S python3 -u

Re:Python unbuffered print v cmd
« Odpověď #2 kdy: 18. 01. 2022, 16:10:13 »
Je to spuštěno na prosté cmd windows příkazové řádce.
Linuxový shebang je tam proto, že se snažím do programů přenesených z linuxu nezasahovat.
Na problém to nemá vliv (jak ostatně uvádím).
Varianta s flush = True se chová stejně blbě:
#!python3 -u
TXT = ""
for I in range(2000):
   TXT += f"{I:09d}\n"
TXT += "konec"
print(TXT, flush = True)

Konec výstupu na terminál:
...
000000990
000000991
000000992
000000993
000000994
000000995
000000996
000000997
000000998
000000999
00
« Poslední změna: 18. 01. 2022, 16:12:02 od zu1234 »

Re:Python unbuffered print v cmd
« Odpověď #3 kdy: 18. 01. 2022, 16:18:34 »
to vypadá na nějaké přetečení bufferu či jiné oříznutí, sice píšeš o unbuffered vypisování, ale tady vše uložíš nejprve do jednéj proměnné a pak vypíšeš najednou, jaký má tenhle test význam?

Odzkoušel jsem teď na čerstvě staženém python3.9 na Windows stanici, že unbuffered přes flush=True funguje. Windows ale není můj velký kamarád a moc ho nepoužívám, abych to znal do hloubky.

Re:Python unbuffered print v cmd
« Odpověď #4 kdy: 18. 01. 2022, 16:38:34 »
Nejedná se zbytečný test, ale ilustraci problému kdy například program, který
vypisuje strukturu tabulek databáze, na windows cmd terminálu skončí jakoby v polovině.
Zajímavé je, že tak děje při VYNUTÉM bufferování.


tecka

  • ***
  • 138
    • Zobrazit profil
    • E-mail
Re:Python unbuffered print v cmd
« Odpověď #5 kdy: 19. 01. 2022, 00:07:52 »
Varianta bez cesty ani náhodou není správnější (ta je úplně blbě), Windows shebang vůbec nepodporuje a ani Python sám ho neinterpretuje (AFAIK). Takže se výsledky svých snah nepokoušej nějak interpretovat, protože v postupu nemáš žádnou logiku.

Re:Python unbuffered print v cmd
« Odpověď #6 kdy: 19. 01. 2022, 08:56:31 »
jakou verzi pythonu máš? Jak to spouštíš?

Koukám, že pokud na výstup zapisuješ unicode (či ascii) znaky, Windows tam má 64Kb buffer (ale očividně ne pro všechny případy https://docs.microsoft.com/en-us/windows/console/writeconsole?redirectedfrom=MSDN), to odpovídá i tomu co ti to vypsalo.

Pokud chceš zapsat libovolné množství dat, musíš zapisovat v binárním módu, tj. -u, to ti ale očividně nefunguje a něco děláš špatně.

Pak je tady další otázka, ono vůbec není bezpečné na consoly vypisovat binární výstup, to může vést k dost podstatné zranitelnosti. Nemůžeš prostě vypisovaný text rozsekat na jednotlivé části a printovat postupně? Co ten tvůj use case má za smysl?

Re:Python unbuffered print v cmd
« Odpověď #7 kdy: 19. 01. 2022, 09:45:18 »
Varianta bez cesty ani náhodou není správnější (ta je úplně blbě), Windows shebang vůbec nepodporuje a ani Python sám ho neinterpretuje (AFAIK). Takže se výsledky svých snah nepokoušej nějak interpretovat, protože v postupu nemáš žádnou logiku.
Z chování programu vyplývá že windows shebang je zpracováván, protože chování programu se mění podle toho zda shebang obsahuje '-u'

Re:Python unbuffered print v cmd
« Odpověď #8 kdy: 19. 01. 2022, 09:55:37 »
Varianta bez cesty ani náhodou není správnější (ta je úplně blbě), Windows shebang vůbec nepodporuje a ani Python sám ho neinterpretuje (AFAIK). Takže se výsledky svých snah nepokoušej nějak interpretovat, protože v postupu nemáš žádnou logiku.
Z chování programu vyplývá že windows shebang je zpracováván, protože chování programu se mění podle toho zda shebang obsahuje '-u'

Ne, windows a jeho příkazové řádky (cmd, powershell) shebang nepodporují. Otázka ale je, jak to vlastně spouštíš, jestli tam nemáš bash přes cygwin či nějak jinak.

Re:Python unbuffered print v cmd
« Odpověď #9 kdy: 19. 01. 2022, 09:57:14 »
jakou verzi pythonu máš? Jak to spouštíš?

Koukám, že pokud na výstup zapisuješ unicode (či ascii) znaky, Windows tam má 64Kb buffer (ale očividně ne pro všechny případy https://docs.microsoft.com/en-us/windows/console/writeconsole?redirectedfrom=MSDN), to odpovídá i tomu co ti to vypsalo.

Pokud chceš zapsat libovolné množství dat, musíš zapisovat v binárním módu, tj. -u, to ti ale očividně nefunguje a něco děláš špatně.

Pak je tady další otázka, ono vůbec není bezpečné na consoly vypisovat binární výstup, to může vést k dost podstatné zranitelnosti. Nemůžeš prostě vypisovaný text rozsekat na jednotlivé části a printovat postupně? Co ten tvůj use case má za smysl?
Python 3.9.1, W10 64bit
Příkaz print provádí konverzi kódování.
Problém vzniká při NEBUFFEROVANÉM výstupu.
Můj příspěvek není o tom že bych to neuměl nějak obejít (například stačí ponechat standartní buffered stav), ale o podivném chování unbuffered výstupu.

ByCzech

  • *****
  • 1 848
    • Zobrazit profil
    • E-mail
Re:Python unbuffered print v cmd
« Odpověď #10 kdy: 19. 01. 2022, 17:44:17 »
Osobně si myslím, že problém je ve Windows console, která má vlastní buffer a než se stihnout vypsat všechna data z bufferu té console, tak program skončí a Windows výpis zastaví. Zkuste to samé mimo Windows.

Re:Python unbuffered print v cmd
« Odpověď #11 kdy: 21. 01. 2022, 09:51:21 »
Osobně si myslím, že problém je ve Windows console, která má vlastní buffer a než se stihnout vypsat všechna data z bufferu té console, tak program skončí a Windows výpis zastaví. Zkuste to samé mimo Windows.
Pokud jsem Vás dobře pochopil, tak vypnutí bufferovaní v pythonu pod windows/cmd je jako z louže pod okap? :-))
Ano, opravdu to tak vypadá.
Když jsem ale běh program prodloužil nějakým blastem za příkazem print, nemělo to vliv na (špatné) chování.

Na Debianu samozřejmě všechno v pořádku!

Re:Python unbuffered print v cmd
« Odpověď #12 kdy: 21. 01. 2022, 12:38:20 »
nedaří se mi tohle chování někde nasimulovat, i několika MB výstup dostanu celý. Můžeš popsat v čem a jak to spouštíš? Co zachytává ten výstup? Vypisuješ ho nebo někam ukládáš? Jakým příkazem spouštíš ten bash script?

Re:Python unbuffered print v cmd
« Odpověď #13 kdy: 25. 01. 2022, 10:20:33 »
Viz přílohy

Re:Python unbuffered print v cmd
« Odpověď #14 kdy: 25. 01. 2022, 13:55:21 »
a můžeš ukázat příkaz jak to přesně spouštíš? Protože cmd.exe prostě nerozumím syntaxi #! a stejně tak těžko budeš mít něco v cestě v /usr/bin/python3, když Windows používá písmena a zpětná lomítka. Chybí mi tady ještě ten jeden dílek do skládačky.

Na screenu je vidět gvim, to směřuje k cygwinu.

Problém totiž může být kdekoliv na cestě a nikoliv pouze ve Windows, tak je potřeba ověřit každou komponentu a zjistit tu, která se nechová podle očekávání nebo to ořezává.