PythonOnWheels ( PoW )

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Ich würde entweder mittels

Code: Alles auswählen

hasattr(x, "__call__")
oder mittels

Code: Alles auswählen

isinstance(x, collections.Callable)
testen. Du suchst wahrscheinlich gerade verzweifelt nach letzterem ^^

Sebastian
Das Leben ist wie ein Tennisball.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Hi EyDu,

jetzt wird es interessant. Metaprogramming ist sowieso spannend, finde ich ..
wenn ich mir die Doku durchlese dann denke ich eigentlich, das

Code: Alles auswählen

func = getattr(instance.function, k)
if callable(func):
    # do something
eigentlich gleichbedeutend sein sollte mit:

Code: Alles auswählen

hasattr(instance.function, "__call__")
laut doku ruft hasattr ja getattr wieder auf. Ist deshalb auch 'sicherer' als callable alleine aber
eben eigentlich nicht als die Kombi wie oben.

(Anm: Damn, kann man eigentlich im Forum statt dem Code button nicht einen python button einfuegen ... :evil: )


Collections.callable klingt wieder sehr interessant. (Hatte ich bisher nicht auf dem Schirm)
Aber da muss ich erst wieder Doku lesen ... ich sage nur ABC (wer das Akronym kennt hat auch schon gelesen ;)

In diesem Rahmen ist auch dieses bugs.pyhton.org ticket interessant.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Zeilen

Code: Alles auswählen

hasattr(instance.function, "__call__")

Code: Alles auswählen

callable(instance.function)
sollten das gleiche Ergebnis liefern. Ich weiß jetzt nicht, was du dem dem k dort vor hast. Wahrscheinlich gibt es da noch kleine Unterschiede, aber ich kann mich gerade weder erinnern, noch habe ich Lust Doku zu lesen :roll:


khz hat geschrieben:(Anm: Damn, kann man eigentlich im Forum statt dem Code button nicht einen python button einfuegen ... :evil: )
Den gibt es, man muss halt nur mal genau hinschauen ;-)

khz hat geschrieben:Aber da muss ich erst wieder Doku lesen ... ich sage nur ABC (wer das Akronym kennt hat auch schon gelesen ;)
ABC = Abstract Base Class, ist eigentlich eine übliche Abkürzung
Das Leben ist wie ein Tennisball.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

man, man, man ....
python-Taste gefunden. Manchmal ist man betriebsblind ;) - Danke

k bezog sich auf die snippets der vorposts:

Code: Alles auswählen

def wrap_class(self, cls):
        #print self.__dict__
        #print dir(self.__class__.__dict__)
        print cls.__dict__.items()
        for k, v in cls.__dict__.items():
            print "key, value:", k,v
            if not k.startswith("__"):
                func = getattr(cls, k)
                print "callable",callable(func)
                if callable(func):
                    print "wrap", k
                    setattr(cls, k, mkwrapper(v))
Ich denke das callable alleine != hasattr

Collections.callable scheint einen gute Option aber ich denke wir
reden hier auch ueber %0,0000001 der Faelle in denen das nicht semantisch
gleichbedeutend ist....Ich starte erstmal wie gezeigt oder schwenke später ...
ist sowieso als plugin geplant, sodass sich die Leute spaeter leicht eine
Alternative Implementierung ziehen (oder entwickeln) können.

Fuer mich ist im Moment wichtig wie ich all die verschiedenen Moeglichkeiten einordnen (und dann entscheiden) kann
damit ich weiterkomme. Ich moechte mich eben auch nicht X Tage mit theoretischen Unterschieden befassen
sondern meine Authentifizierung hinbekommen ;)
Aber die soll nicht 'gestickt/gefrickelt' sondern schon so sein, das es den Empfehlungen der community
entspricht.

Bin parallel gerade in der PyPi Paketerstellung fuer Pow...
ist auch ein bindendes Thema....
Deshalb schonmal sorry falls ich erst verspaetet antworte ....

P.S.:ABC = Abstract Base Class, ist eigentlich eine übliche Abkürzung
danke fuer das Salz in der Wunde ;)
http://www.pythononwheels.org
11to1 sparetime development and all pm.
BlackJack

@khz: Willst Du eigentlich wirklich alles wrappen was aufrufbar ist, oder nur Methoden? Kennst Du das `inspect`-Modul?

Code: Alles auswählen

In [70]: inspect.getmembers(B, inspect.ismethod)
Out[70]: [('a', <unbound method B.a>), ('b', <unbound method B.b>)]
'a' ist von einer Klasse `A` geerbt — hast Du auch an so etwas gedacht, damit Du geerbte Methoden nicht mehrfach wrappst?
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

@BlackJack,


nur Methoden und da auch nur die, die der Entwickler in einem Dict festlegt.

Hier nochmal der eigentliche Anlass bzw die Grundidee als Skizze:


Der Entwickler schreibt eine Klasse:
und Kann dann ueber die Protector Klasse
einfach seine Methoden schützen.

Code: Alles auswählen

import Protector

class A(object):
    def __init__(self):
        self.a = None
        self.b = None
        # soll dann bedeuten
        # schuetze (wraped) die Methode b_method und prüfe auf admin
        # wenn ok wird b_method ausgeführt, sonst eine Exeption geschmissen.
        Protector.lock ( { "b_method" : "admin" } )
    
        
    def a_method(self):
        #irgendwas
        pass
    
    def b_method(self):
        #irgendwas anderes
        pass
    

was lock wirklich macht ist dann abhaengig vom der Implementierung
der Klasse Protector. Erster Bedarf ist Authentifizierung (und Authorisierung).
Protector soll dann ein plugin fuer PoW sein das durch Austausch der Klasse ersetzt werden
kann. Also möglichst lose gekoppelt.

Ich finde den Call einer Lock Methode an einer Stelle (fuer den Entwickler) schoener
und übersichtlicher als jede Einzemethode mit einem Dekorator verzieren zu muessen.
Da sieht man auch später auf einen Blick was in der Klasse geschützt ist und
wie.

Ich moechte das Wrappen dann auch gerne für 'dynamische' pre und post filter
nutzen. Also wie Stefan schon schrieb. Dann habe ich ein Verfahren, was ich prima fuer
mehrere Zwecke einsetzen kann.

Wie das bei Stefan und EyDu schon rueberkam gibt es da aber eben einige Moeglichkeiten
die syntaktisch verschieden sind. Ich moechte natuerlich gerne ein 'richtiges/gutes'
bzw bewaehrtes nehmen.

Ich werde mich jetzt nochmal verstaerkt mit
collections.callable und inspect befassen. Damit ich verstehe was passiert.
Dein Stichwort mit Basisklassen bzw EyDus collections geben einen guten Anstoss.

@EyDu: Bis Dahin werde ich auf deinen Vorschlag hasattr(x, "__call__") umschwingen, da das
aus meinem Zweizeiler einen Einzeiler macht. Ich wäre ja blöd wenn ich das nicht mitnähme ;)
http://www.pythononwheels.org
11to1 sparetime development and all pm.
deets

Ich kann deine Argumente zur Nachvollziehbarkeit ueberhaupt nicht nachvollziehen...

Schau dir doch mal an, wie zB TurboGears2 das macht: Es gibt eine Klassenweite Einstellung die fuer alle Methoden gilt. Und pro Methode per Dekoration eine.

Und das ist *wesentlich* besser nachvollziehbar, denn dann sehe ich an der Methode, an der ich arbeite, ob und wie die geschuetzt ist. Und ich laufe auch nicht Gefahr, dass ich in einem irgendwo rumfliegenden Dictionary einen Methodennamen nicht exakt gleich geschrieben habe. Mal abgesehen davon, dass das eine unnoetige Doppelung der Schreibarbeit ist. Und last but not least: wenn sich ein Methodenname aendert, bleibt der Dekorator automatisch auf Stand - dein Ansatz hingegen erzwingt einen weiteren Denkschritt, der gerne vergessen werden kann - und dann schlaegt der Default zu, und das heisst uU oeffentliche Nutzbarkeit.

Alles in allem wenig ueberzeugend finde ich.

http://turbogears.org/2.0/docs/main/Aut ... horization
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hab jetzt nicht alles detailliert gelesen, aber mir scheint, du willst Methodenaufrufe abhängig von Zugriffsrechten schützen? Da dir der Dekorator-Ansatz ja scheinbar nicht gefällt, könntest du vielleicht von einer Klasse `Lockable` erben. Die zu schützenden Methoden verwaltest du in einem Instanz- oder evtl auch Klassenattribut. Ich würde dabei nicht, wie in deinem Beispiel, über Klassennamen als Strings gehen, sondern direkt `self.methode` registrieren. Die geerbte Logik der `Lockable`-Klasse kümmert sich um die Sache mit der Berechtigung. Wrappen würde ich wohl einfach `__getattr__()`.

Ich fände es aber mit Dekorator irgendwie auch einfacher.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

@deets
Ich kann deine Argumente zur Nachvollziehbarkeit ueberhaupt nicht nachvollziehen...
Hihi, lustich ;)

Ich finde deine Argumente nachvollziehbar. Allerdings ist es mir
persönlich trotzdem lieber das zentral zu machen.
Ich nehme mal als Beispiel das ich lieber sage:
Macht vorm Rausgehen alle Fenster zu
als das ich jemandem sage:
Also bevor ihr rausgeht, mach bitte das Fenster zu ... und das .... und das (und gehe durchs ganze Haus..)
Andererseits muss man zum prüfen ob ein Fenster echt zu ist, natürlich DAS Fenster ansehen ...
Allerdings kann man das real im Programm dann auch an der zentralen Stelle sehen.
Wenn es eben im Dict steht ist es zu, sonst nicht.

Da aber eben die Geschmaecker verschieden sind und ich das Framework ja nicht fuer mich alleine
mache, werde ich beides anbieten.

Als Methoden zentral: (Turbogears macht das ja uebrigends auch zentral um alle zu abzusichern )

Code: Alles auswählen

protect_all( { "method1" : "parameter", "method2" : "parameter"}...)
protect_all_except( ["method1", "method2", ...])
protect_only( { "method1" : "parameter", "method2" : "parameter"}...)
all schuetzt dann alle
all_except schuetz alle bis auf die genannten Ausnahmen
only schuetz alle explizit genannten.

Idealerweise kann man das dann auch weglassen und einen Dekorator verwenden.
=> Das ist dann das Ziel aus Usability Sicht.
Zuletzt geändert von khz am Freitag 14. September 2012, 23:11, insgesamt 3-mal geändert.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

@snafu:

ja, hatte ich tatsaechlich erst auch ueberlegt.

Aber dagegen spricht fuer mich, das ich ja ueber diesen Weg einen plugin Mechanismus realisieren moechte.
Wenn ich Vererbung nähme und man hat viele Plugins, haette man eben auch viele Basisklassen.

Ich finde Konstrukte wie:

Code: Alles auswählen

class A(B,C,D):
einfach unschön ..

Ansonsten gebe ich dir voellig recht. Wie gesagt, hatte ich auch gedacht und meine auch das das fuer
_einen_ Fall gut gehen wuerde.

Bzgl der Dekorator denke ich, das ich das auf Jeden Fall mit anbieten sollte. (Du bist ja schon der 2. von 2 ;)
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

kurzer Einwurf von der Seite:

ich habe den Blog endlich online gebracht.
so sieht es dann aus.

Ist im Prinzip derselbe den im im Webcast erstelle.
Jetzt allerdings mit einfachem login, pagination und markdown support.

Als naechstes kommen dann comments. (Das ist dann der Ernstfall fuer die has_many
und belongs_to relationen.)

kennt jemand ein leicht einzubindendes Captcha modul ?
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

@snafu, @deets

bitteschoen ;) auf vielfachen Vorschlag kann man jetzt die actions 'dekorieren':
Danke nochmal für das feedback.

Code: Alles auswählen

@protect
def list( self, powdict ):
    """ Standard PoW action to return all records of the related model """
    res = self.model.find_all()
    return self.render(model=self.model, powdict=powdict, list=res)
@protect prüft dann ob man als user angemeldet sit oder nicht, bevor die action ausgeführt wird.

ich werde das noch um Parameter für den decorator erweitern, sodass man user und/oder
Rolle für den Zugriff auf die Action vorgeben kann.

Also etwa

Code: Alles auswählen

@protect(user, role)
def list( self, powdict ):
    """ Standard PoW action to return all records of the related model """
    res = self.model.find_all()
    return self.render(model=self.model, powdict=powdict, list=res)
Kleiner Nachtrag zu Dekoratoren

Code: Alles auswählen

@meine_funktion_die_andere_dekoriert
def a_standalone_func():
   pass
sind gleichbedeutend mit:

Code: Alles auswählen

a_stand_alone_function = meine_funktion_die_andere_dekoriert(a_stand_alone_function)
(siehe super decorator Erläuterung)

Für die oben geführte Diskussion (zentral definieren oder lokal dekoriereren) bedeutet das,
das ich eventuell zwei Fliegen mit einer Klappe schlagen kann.

Also decorator wie oben implementieren und dann, mit dem im Petto,
ueber eine Liste iterieren und in der Form

Code: Alles auswählen

setattr (obj, meth, decorator(method))
alles schützen. Bsp.-Weise in __init__ des Objektes.

Sieht irgendjemand was, was dagegen spräche ? Habs noch nicht getestet ....
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

http://www.pythononwheels.org
11to1 sparetime development and all pm.
Antworten