Zugriff auf jedes Attribut abfangen...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 4. Januar 2007, 13:40

Ich möchte gern wieder hilfreiche Fehlermeldungen machen... Wenn ein Plugin keine config hat, dann darf es auch diese nicht existierende benutzten.
Der einfachste weg ist natürlich das plugin_cfg Objekt nicht existent zu machen. Es kommt dann halt immer ein Attribut Fehler, bei egal welchem Zugriff...
Aber ich möchte gern einen Aussagekräftigeren Fehler zurück liefern. Deswegen packe ich zwar ein plugin_cfg Objekt in das Plugin, aber das ist diese Klasse:

Code: Alles auswählen

class NoPluginConfig(object):

    def __init__(self, module_name):
        self.module_name = module_name

    def __contains__(self, key): self._error()
    def has_key(self, key): self._error()
    def __repr__(self): self._error()
    def __str__(self): self._error()
    def get(self, key): self._error()
    def __setitem__(self, key, item): self._error()

    def commit(self):
        # Der Module-Manager ruft immer commit auf ;)
        pass

    def _error(self):
        try:
            import inspect
            for stack_frame in inspect.stack():
                # Im stack vorwärts gehen, bis außerhalb dieser Datei
                filename = stack_frame[1]
                lineno = stack_frame[2]
                if filename != __file__:
                    break

            filename = "...%s" % filename[-25:]
            fileinfo = "%-25s line %3s: " % (filename, lineno)
        except Exception, e:
            fileinfo = "(inspect Error: %s)" % e

        msg = (
            "Error: Plugin/Module '%s' has no plugin-config!"
            " But in %s you access to the plugin_cfg object ;)"
            " If you would like to use plugin_cfg, you must setup your"
            " module/plugin config file!"
        ) % (self.module_name, fileinfo)
        raise AttributeError(msg)
Ist ein wenig umständlich gelöst, wie ich finden... Aber experimente mit __getattribute__() oder __getattr__() scheiterten immer :(
Es muß doch möglich sein, eines der beiden Methoden zu nutzten um jeden Zugriff mit der _error() Meldung zu quitieren...

Zur Info: Das config-Objekt kann im Grunde alles sein, was mit pickle verarbeitet werden kann.

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 4. Januar 2007, 14:10

Korrigier mich wenn ich falsch liege (das vermute ich nämlich, weil es zu einfach ist), aber ich habe Paste #553 angelegt, in der so etwas sowohl mit __getattr__ (was ist eigentlich sinnvoller finde) als auch mit __getattribute__ (was natürlich total umständlich ist, aber ich weiß nicht genau was du willst) gelöst wird.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 4. Januar 2007, 14:22

Danke, das bringt mich ein Stückchen weiter...
Nun sieht es so aus:

Code: Alles auswählen

class NoPluginConfig(object):

    def __init__(self, module_name):
        self.module_name = module_name

    def __getattr__(self, name):
        self._error()

    def __contains__(self, key): self._error()
    def __str__(self): self._error()
    def __setitem__(self, key, item): self._error()

    def commit(self):
        # Der Module-Manager ruft immer commit auf ;)
        pass

    def _error(self):
        msg = (
            "Error: Plugin/Module '%s' has no config!"
            " But you access to it ;)"
            " If you would like to use plugin_cfg, you must setup your"
            " module/plugin config file!"
        ) % self.module_name
        raise AttributeError(msg)

p = NoPluginConfig("jojo")
p.commit() # Soll immer ignoriert werden!

#~ print type(p)
#~ p.get("key", "")
#~ p.has_key("jojo")

# Sachen, die nicht mit __getattr__ abgedeckt werden:
p[32] = 1 # Ohne __setitem__ -> TypeError: object does not support item assignment
"test" in p # Ohne __contains__ -> TypeError: iterable argument required
print p # __str__ -> Soll auch Fehler auslösen
Ich muß allerdings dennoch ein paar Methoden explizit mit _error() "verknüpfen".

Ich muß ja damit rechnen, das der User das Objekt wie ein dict benutzt ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 4. Januar 2007, 17:38

Ha, ich mache es anders... Ich leite die Klasse nicht von object ab, sondern von dict, dann komme ich nur mit __getattr__ aus :lol:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Donnerstag 4. Januar 2007, 19:35

Das mit dem Stackframe ist ja schon nahe an Voodoo. :-)

Ansonsten hätte man das "Keine-Config-Objekt" sicher auch mit einem Descriptor lösen können.

http://www.python.org/doc/2.4.1/ref/descriptors.html
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 5. Januar 2007, 10:02

Kannst du dazu ein kleines Beispiel aufzeigen?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Freitag 5. Januar 2007, 13:38

Hm, kann sein das ich das Problem missverstanden habe. Ich dachte es handelt sich bei der Konfiguration um ein Attribut. Wenn die global in einem Modul ist, dann geht's natürlich nicht mit einem Descriptor.

Ansonsten kann man ein Klassenattribut, das immer "Ausnahme" schreit wenn man es auch nur anfasst, so schreiben:

Code: Alles auswählen

class DontTouchMeAttribute(object):
    def __get__(self, instance, owner):
        print instance, owner
        raise Exception("Hey, I'm not here.  Really...")

class Spam(object):
    config = DontTouchMeAttribute()

def main():
    spam = Spam()
    print spam.config
Antworten