Seite 1 von 1

Alternative zu eval() ?

Verfasst: Montag 28. April 2008, 13:01
von jens
Ich möchte, das ein User Daten eingeben kann, die aber nur vom Typ unicode, string, number, float, tuple, dict usw. sind.
In dem Fall eval() zu benutzten ist zwar nächstliegend, aber doof. Wie kann ich das anders machen???

btw. Der User kann die Daten über ein html Formular eingeben, aber das ist eigentlich egal.

EDIT: Doch noch was gefunden:
safe_eval: http://aspn.activestate.com/ASPN/Cookbo ... ipe/496746 - macht aber ehr eine blackliste... Ein versuch es mit einer whitelist zu probieren:
http://www.python-forum.de/post-45714.html#45714 - das schaue ich mir mal näher an...

Re: Alternative zu eval() ?

Verfasst: Montag 28. April 2008, 13:11
von keppla
jens hat geschrieben:Ich möchte, das ein User Daten eingeben kann, die aber nur vom Typ unicode, string, number, float, tuple, dict usw. sind.
Würde dir da vielleicht ein JSON-Parser weiterhelfen? JSON kann doch eigentlich alles genannte, und das auch syntaktisch gleich zu python. (ok, unicodestrings nich, aber sofern du nicht "bytearrays" brauchst ist das doch sogar ein gewinn)

Verfasst: Montag 28. April 2008, 14:36
von jens
Gute Idee. Aber ich möchte erstmal bei der Python Syntax bleiben. Ich sollte das aber mal im Hinterkopf behalten...

Ich hab noch was gefunden: http://aspn.activestate.com/ASPN/Cookbo ... ipe/364469

Verfasst: Montag 28. April 2008, 14:49
von Y0Gi
Du suchst nicht zufällig etwas zur Form-Validierung wie etwa WTForms?

Verfasst: Montag 28. April 2008, 14:57
von jens
Ne, da nehme ich django's newforms ;)

Also um was es eigentlich geht: In PyLucid gibt es die "Preferences" Tabelle. Einstellungen, die Plugins und das Basis System hinterlegen können. Damit das ganze sehr flexibel ist, nutzte ich pickle... Bisher gibt es keine Möglichkeiten die Einstellungen zu verändern :(
Als erster Schritt, damit der Admin die Einstellungen bearbeiten kann, ist halt einfach alles mittels pprint in einer html Form editierbar zu machen. (Also pro Einstellung, ein Text-Input).
Auch wenn das nur der Admin darf, möchte ich aber ehr ungern eval() benutzen um die Eingaben in Python Objekte zu wandeln... Deswegen die Frage hier ;)

Auf langer Sicht gesehen, sollte ein Plugin allerdings newforms dafür nutzten, macht ja eigentlich auch mehr Sinn... Dennoch sollte es diese Form der editierbarkeit dennoch zusätzlich geben...

EDIT: Das ist daraus geworden:
http://pylucid.net:8080/pylucid/browser ... ta_eval.py

Verfasst: Dienstag 29. April 2008, 15:01
von Y0Gi
Ich würde sowas so lösen, dass zu jedem Konfigurationswert, der z.B. in der Datenbank oder anderswo definiert ist, zugleich auch ein Typ und evtl. ein Default-Wert festgelegt sind. Möchte ein Benutzer einen Wert ändern, wird anhand des zugewiesenen Typs versucht, aus dem Eingabestring dieser Typ zu erzeugen. Klappt das, gut; wenn nicht, Fehlermeldung ausgeben. Deckt das nicht die von dir gewünschte Flexibilität ab?

Verfasst: Dienstag 29. April 2008, 15:07
von jens
Naja, ich muss da generell nochmal intensiver drüber nachdenken.

Evtl. gebe ich bei jedem Einstellungswert direkt auch den passenden newforms-Field an. Dann könnte man sehr einfach eine passende html-form mit Validierung erzeugen...

Am besten erstelle ich erstmal eine Liste mit potenziellen Einstellungswerten, um zu sehen, was überhaupt i.d.R. gespeichert werde muß...

Verfasst: Mittwoch 30. April 2008, 08:28
von jens
Auch wenn ich es vielleicht nicht brauchen werde, hab ich in data_eval.py die Unterstützung für datetime und timedelta Einträge implementiert:

http://pylucid.net:8080/pylucid/changeset/1542

Keine Ahnung ob das die beste Variante ist, es zu implementieren, aber es funktioniert so und ist druch das dict ALLOWED_CALLABLES erweiterbar...

Verfasst: Mittwoch 30. April 2008, 09:53
von sma
Ich würde dafür einen eigenen Parser schreiben. Ich habe 2x ein Microrahmenwerk für PEGs aka Parserkombinatoren gepostet, damit sollte das in 1-2 Stunden realisierbar sein.

Stefan

Verfasst: Mittwoch 30. April 2008, 10:00
von jens
Warum sollte ich mir einen eigenen Parser schreiben, wenn es compile schon für mich erledigt?

Verfasst: Mittwoch 30. April 2008, 10:21
von sma
Weil eval() prinzipbedingt unsicher ist. Ich dachte, den auszuführenden Code könnten User eingeben. Da würde ich nur meinem eigenen Parser trauen.

Stefan

Verfasst: Mittwoch 30. April 2008, 10:22
von jens
Hast du dir die sourcen überhaupt angesehen?
http://pylucid.net:8080/pylucid/browser ... ta_eval.py

Ich nutzte kein eval()

Verfasst: Mittwoch 30. April 2008, 10:35
von mitsuhiko
Sollte es ast.py in die Stdlib schaffen kannst du "ast.literal_eval" nutzen: http://dev.pocoo.org/hg/sandbox/file/tip/ast/ast.py

Verfasst: Mittwoch 30. April 2008, 10:42
von sma
Ich habe ehrlich gesagt, auf die Überschrift reagiert und das, was du in deinem ersten Posting von ASPN erwähnt hast, nicht deine fertige Lösung. In Google AppEngine-Zeiten würde ich ja empfehlen, nicht auf `import compiler` zu bauen. Warum enthält der UnitTest `testLineendings` eigentlich keine Asserts?

Stefan

Verfasst: Mittwoch 30. April 2008, 10:48
von Y0Gi
Die Sache schreit doch: Wenn man `eval()` benutzt, muss man einen verdammt guten Grund haben, und ich sehe hier keinen, im Gegenteil (User-Input). Also muss da was anderes her.

P.S.: Das hier bezieht sich ebenfalls auf den Titel und die ursprüngliche Frage. Nur, damit spätere Leser das nicht falsch verstehen können.

Verfasst: Mittwoch 30. April 2008, 11:21
von mitsuhiko
sma hat geschrieben:Ich habe ehrlich gesagt, auf die Überschrift reagiert und das, was du in deinem ersten Posting von ASPN erwähnt hast, nicht deine fertige Lösung. In Google AppEngine-Zeiten würde ich ja empfehlen, nicht auf `import compiler` zu bauen. Warum enthält der UnitTest `testLineendings` eigentlich keine Asserts?
AppEngine saugt sowieso und _ast funktioniert auf der AppEngine mit ein wenig Hackery. Außerdem ist AppEngine sowas von weit weg von einer regulären Umgebung, dass du da nicht drauf achten musst außer du entwickelst speziell für die.

Verfasst: Mittwoch 30. April 2008, 14:38
von jens
So, hab das ganze nochmals uberdacht und neu implementiert... Ist aber noch nicht ganz fertig: http://pylucid.net:8080/pylucid/changeset/1544
Ich nutzte dann statt pickle mein data_eval um die Daten in der Datenbank abzulegen. Dafür kann der user aber dann einfach nur die newforms erzeuge html form ausfüllen. Da pickle quasi durch data_eval() ersetzt ist, kann nun ein User im django admin panel die Daten verändern...