ugrás a tartalomhoz

Flask - nem értem

mind1 valami név · 2023. Ápr. 30. (V), 09.16
Van egy ilyen primitív program:
from flask import Flask, request


app = Flask(__name__)
counter = 0
print(f"....{counter}....")


@app.route("/inc")
def inc():
    x=request.args.get("x")
    print(f"Counter: {counter}")
    if x:
        count += int(x)
    return f"+++ {counter} +++"


if __name__ == "__main__":
    app.run()
Ha http://localhost/inc formában szólítom meg, akkor hibátlanul visszaad nullát (vagy amit felül beállítottam a counter értékeként).
Ellenben, ha kap egy x paramétert: http://localhost/inc?x=1, akkor internal server error az eredmény. A valódi hiba: "local variable 'count' referenced before assignment
Ez valami flask hülyeség, nem is az a kérdés, hogyan javítsam ki, csak arra nem találok értelmes választ, hogy ha nem akarom módosítani, akkor miért látja mégis?
Mert a flasknek van olyanja, hogy app context, meg request context és amikor a http get-re válaszol, akkor az utóbbi él, normális, hogy nem tud mit kezdeni a contexten kívül definiált változókkal. De akkor read only miért látja?
 
1

Ennél már csak az a szebb,

mind1 valami név · 2023. Ápr. 30. (V), 09.33
Ennél már csak az a szebb, hogy beleírtam a fenti kódba egy app.app_context() hivatkozást, és azóta normálisan viselkedik: már a legelső hivatkozásnál visít a counter változóra, azt követően is, hogy eltávolítottam a contextes sorokat...
Sajnos csak homokozóban csináltam, nincs nyoma sehol. Se log, se git history :(
2

global / local

Endyl · 2023. Ápr. 30. (V), 14.58
Csak egy tipp, de ha eredetileg úgy futott a kód, mint ahogy itt van (if-en belül count van counter helyett), akkor ha nem lép bele az if-be, akkor nem nyúl problémás változóhoz a kód. Ha viszont már az if-en belül is counter van, akkor mivel nincs global counter deklaráció a függvényben, és mivel alapesetben a függvények csak olvasni tudnak globális változókat, írni nem, az if-en belüli hozzárendelés elfedi lokális változóként a globális countert a parszolás során, viszont nincs inicilizálva a változó, így már if-be futás nélkül és azzal is problémás a counter-re való hivatkozás a visszatérési értékben.
4

Már nem tudom az eredetit

mind1 valami név · 2023. Ápr. 30. (V), 16.43
Már nem tudom az eredetit ellenőrizni, ezt meg itt gépeltem, szóval akármi is lehet. :)

Amit a global módosításáról írsz, az 3-as pythonban van így? (Költői, majd megnézem)
Ezzel eddig nem találkoztam. Igaz, a globális változókat kerülöm, mint a Patás a tömjént. :)


Off: repedt/törött bordával vajon lehet biciklizni? :D (IHM, Öreg néne bőrzekéje: "... elütött egy román traktor, de szar ez így reggel hatkor..." :D)
3

Wow... és tényleg: ha a

mind1 valami név · 2023. Ápr. 30. (V), 16.34
Wow... és tényleg: ha a függvény belsejébe berakok egy "global counter" sort, akkor máris működik (???).

Az eredeti cél az volt, hogy a pythonanywhere-en azt írják, a free usernek csak egy worker jár, én meg következetesen két python processzt látok futni.
Úgy emlékeztem, hogy a workerek mind saját példányt futtatnak az applikációból, ergo ha az indításkor egy változóba berakok egy random integert, amit a requestek kiszolgálásakor visszaküldök, akkor minden instance más értéket fog visszaadni.
Aztán kipróbáltam a saját gépemen, 8 worker processzt indítva uwsgi és gunicorn alatt.
Az eredmény azonos: ugyanazt a számot adta vissza mind, holott a logból látszott, hogy más-más processz szolgálta ki a párhuzamosan érkező requesteket. És az inicializáló kód is csak egyszer futott le.
Na itt jött, hogy akkor megnézem, tényleg globális-e ez a változó, mi történik, ha requestenként növelem az eredeti számot?
És ez akadt meg azon, hogy ahogy írtad: a globális változót felülírta a lokális példány, ami még nem volt inicializálva.

Szóval a szokásos: hiányosan átfutott doksi, nulla gyakorlat.
5

És kezd összeállni a dolog: a

mind1 valami név · 2023. Ápr. 30. (V), 16.50
És kezd összeállni a dolog: a wsgi szerver lefuttatja az alkalmazást tartalmazó programot, majd a végén forkolja magát annyifelé, ahány workert indítottam.
Így csak egyszer fut le az, amit én inicializáló kódnak nevezek (nem tudom, mi a tisztességes elnevezése), ezért van az, hogy akárhány példányban fut, az elején generált random érték mindben ugyanaz.

A globallal megspékelt változatot több workerrel indítva, ha egyszerre letámadom 10-20 klienssel, akkor láthatóan mindben 0-ról indul a counter és némelyik felmegy akár 2-ig is :)

Szóval még egy nyomorult long poll-os chat applikáció sem annyira egyszerű, mint ahogyan azt én képzeltem, mivel az adott oldalon nincs lehetőségem background processzt futtatni, a globális változóban tárolt chat meg ugye így nem működik. Illetve működhet még így is, csak már gusztustalanul (pl. zeromq-val feliratkozni a localhost kiválasztott portjára, aztán amelyik szerver kap egy új üzenetet, azt kirakja ide broadcast-ként stb. De ez már gányolás, nem programozás)
6

blueprint - mintha bugos lenne

mind1 valami név · 2023. Május. 3. (Sze), 20.42
from flask import Flask, jsonify
from chat.app import bp as chat_bp


app = Flask(__name__)
app.register_blueprint(chat_bp, url_prefix="/chat")

@app.route("/")
def index():
    b = app.blueprints["chat"]
    print(dir(b))
    return jsonify({"static folder":b.static_folder, "static_url_path": b.static_url_path, "url_prefix":b.url_prefix })
Én úgy gondolnám, hogy ha a register_blueprint tartalmazza a url_prefix értékét, az a korrekt eljárás, mivel a blueprintben nem tudhatom előre, hogy a főprogram hová akarja irányítani.
Ott a gond, hogy ha a Blueprint létrehozásakor adom meg a url_prefix értékét, akkor a fenti kódból a megfelelő könyvtár jön vissza válaszként, ha így csinálom, ahogy itt fenn, akkor a url_prefix értéke null. Maga az app így is működik, de nem tudom lekérni a blueprintek-hez tartozó prefixet.
Vajon miért?
(a chatgpt "kijavította" úgy, hogy törölte a print sort. :D)
7

Nem állítom, hogy látom benne

mind1 valami név · 2023. Május. 3. (Sze), 21.23
Nem állítom, hogy látom benne a logikát: https://github.com/pallets/flask/issues/4086

És minél tovább túrom a google-t és a doksikat, annál kevésbé értem: elméletileg az app.blueprints változó tartalmazza a regisztrált blueprintek adatait. De úgy tűnik, csak az eredeti adatokat adja innen vissza, a register_blueprint ebbe nem szól bele...

ui: véletlenül rossz linket tettem be eredetileg. Szóval nem értem. Ha több prefix-szel regisztrálom, akkor több példányban fog szerepelni az app.blueprints-ben. Viszont az eredeti példányban megadott url_prefix-et nem módosítja és ez állítólag normális. Viszont így ugye nem lehet lekérdezni kívülről, hogy milyen címekre van beregisztrálva az adott modul.
Hülye dolog.
8

Flask.session - ezt még kevésbé értem...

mind1 valami név · 2023. Május. 4. (Cs), 22.52
Ahhoz, hogy a flask.session-t használni lehessen, be kell állítani az app.secret_key-t valami random értékre, amivel (állítólag) a Flask kódolja a session cookie-t.
Aham... A firefox development tools Network fülén meg lehet lesni a hálózati kommunikációt, pl. azt a requestet, aminek a válaszában cookie érkezik. Az ember kimásolja a Set-Cookie: sorból a session= után álló random(?) karaktersort az első pontig, majd az egészet átadja pythonban a base64.urlsafe_b64decode() függvénynek és csodálkozik/anyázik tetszés szerint.
Ugyanis ott van a cookie tartalma kódolatlanul. Kérdem én: akkor mi a bánatos lóizé értelme van kötelezően előírni az app.secret_key kitöltését?

Ez most onnan jött, hogy meg akartam nézni, mit írok ki valójában a session cookie-ba, amikor oda adatot küldök, mert valami nem pont úgy működött, ahogy elképzeltem. De nem lehet, mert látszólag titkosítva van. De nem. O.K., arra jó ez a "védelem", hogy ne lehessen manipulálni könnyedén a kirakott adatokat, na de ha fejlesztek és debuggolni akarom a saját szemetemet, akkor ennek miért kell keresztbe tenni? (a kérdés költői :) )

Ami viszont nem az: újabban nektek is a geeksforgeeks oldalt hozza elsőként a google IT témákban? Azt írja, hogy nem személyre szabott találat, de három-négy napja bármit keresek, mindig ez van a tetején és néha véletlenül nyitom meg, máskor meg ez az egyetlen ami legalább közelítőleg arról szól, amit keresek. :(
9

DoS-oltam magam :D

mind1 valami név · 2023. Május. 15. (H), 07.12
Hát erre nem számítottam.
Régebben, mikor ilyenekkel foglalkoztam, Debiant használtam, nem emlékszem, hogy gond lett volna 800-1000 párhuzamosan futó processzből.
Igaz, akkoriban a forkbomb (
:(){ :|:& };:
) még simán fagyasztott minden alapbeállítású gépet.
Kíváncsi voltam, mi történik ha egy, majd több worker processz mellett beesik úgy 1000 request egy olyan apphoz, ami sqlite-ot használ.
Egyelőre ott tartok, hogy minimum a fele elhasal a különböző op.rendszer limitek miatt, a flask, a uwsgi még köszönik, jól vannak.
Előbb az egyszerre nyitva tartható fájlok száma okozott gondot (ulimit -n), de mikor a socketek kezdtek elfogyni és a kerneltől is jöttek figyelmeztetések a túlterhelésről, akkor mentem aludni. :)
A teszt egyébként annyi volt, hogy van egy flask api, ami a requestben kap egy stringet, amit beszúr a teszt táblába, kliens oldalon meg bash alatt, egy 1000 soros syslog részlet minden sorából generálok egy curl parancsot, amit backgroundban futtatok. Ez így 1001 processz kliens oldalon + 12-14 a szerveren.
Ettől az ubuntu megsértődött. :)
10

A folytatás már izgalmasabb:

mind1 valami név · 2023. Május. 15. (H), 10.37
A folytatás már izgalmasabb: a rengeteg log üzenet közt elveszett egy "apróság"...
"uWSGI listen queue of socket "
A fájl limiten túl ennyi volt az össz problémája: több socketet kellett engedélyezni a uwsgi-nek.
Azért érdekes volt, hogy ehhez képest a curl-ke közül ami hibára futott, mind 52-es exit code-ot produkált, ami tudtommal az Out of memory jelzése.