Python Makros in LibreOffice / OpenOffice: Problem mit import

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
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

Hallo,

ich versuche aktuell, mir das Programmieren von Python-Makros in LibreOffice beizubringen. Basis sind überwiegend verschiedene Programmschnipsel aus dem Internet und einige Tutorials, eine gute Dokumentation konnte ich bisher nicht finden. Falls jemand da etwas kennt, wäre ich für Hinweise dankbar.

Derzeit kämpfe ich mit dem Problem, daß ich selbsterstellte Module nicht importieren kann. Unter "Meine Makros" wird die zu importierende Datei zwar angezeigt, aber wenn ich sie in eine andere zu importieren versuche, bekomme ich den Fehler:

Code: Alles auswählen

Ein Scripting Framework Fehler trat während der Ausführung vom Python-Skript vnd.sun.star.script:Auswertung01f.py$machAuswertung?language=Python&location=user auf.

Meldung: <class 'ImportError'>: No module named 'codeauslagerung01a'
  File "...\LibreOffice 5\program\pythonscript.py", line 993, in getScript
    mod = self.provCtx.getModuleByUrl( fileUri )
  File "...\LibreOffice 5\program\pythonscript.py", line 453, in getModuleByUrl
    exec(code, entry.module.__dict__)
  File "...\LibreOffice\4\user\Scripts\python\Auswertung01f.py", line 3, in <module>
    import codeauslagerung01a
  File "...\LibreOffice 5\program\uno.py", line 347, in _uno_import
    return _builtin_import(name, *optargs, **kwargs)
Lasse ich die Datei im Python-Editor ausführen, passiert sie diesen import-Versuch klaglos (scheitert dann aber am folgenden uno-import).

Die Datei liegt offenbar in einem als Pfad bekannten Bereich, insofern bezweifle ich, daß eine komplette Pfadangabe wirklich weiterhilft, aber wie sonst kann ich diese Datei für den import 'bekannt machen'? Andererseits sollten die import-Anweisungen ja vor dem eigentlichen Programmcode stehen, wie mache ich das, wenn ich erst die Pfadangabe 'erarbeiten' lassen muß?

System-Details: Betriebssystem Windows, Python 3.4, LibreOffice 5.3
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

Libreoffice hat da seine "eigenen" Vorstellungen vom "import-Suchpfad" du musst die importierbaren Module relativ im Pfad …/Scripts/python/pythonpath/… speichern.
Oberhalb von …/Scripts/ ist dann entweder dein Benutzerkonfigurationsverzeichnis oder ein spezifisches Dokument oder das Verzeichnis deiner Extension ( .oxt )
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

Danke erst einmal für die Hile :-) .

Nur verstehe ich noch nicht: Was ist 'pythonpath' an der Stelle? Ein weiterer Unterordner?

Die Dateien liegen exakt an der Stelle, nur eben in Scripts/python (ohne weiteren Unterordner), was nach Auskunft eines Tutorials an sich eine korrekte Platzierung sein soll. Aber das ist eben die Sache mit Tutorials, sie neigen dazu, Fehler in die Welt zu setzen.
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

Ein Nachtrag (Beiträge editieren ist hier nicht möglich, oder habe ich die Option irgendwo übersehen?): Quelle für die von mir gewählte Platzierung der Dateien war wohl https://wiki.openoffice.org/wiki/Python ... o_language .
Ich gehe davon aus, daß in diesem Bereich OpenOffice und LibreOffice parallel funktionieren.

Ein anderer Ansatz, den ich vielleicht testen würde, ist: Ist es möglich, daß LibreOffice nur *.pyc-Dateien zum Import vorsieht?
Allerdings habe ich noch nie die Notwendigkeit gehabt, eine py-Datei 'manuell' zu kompilieren, stehe also etwas auf dem Schlauch, wie das geht. Ich bin auf py_compile.main(args=None) gestoßen, das scheint mir von der Beschreibung her zu passen, aber wie setze ich diesen Befehl sinnvoll ein? Oder ist ein anderer Befehl geeigneter?
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

merlem hat geschrieben:
Nur verstehe ich noch nicht: Was ist 'pythonpath' an der Stelle? Ein weiterer Unterordner?
Exakt das ist es, ein Unterordner mit dieser Bezeichnung.
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

Danke noch einmal! :-)
In dem Unterordner wird das Modul immerhin gefunden. Allerdings scheint das trotzdem alles nur vergebliche Liebesmüh' gewesen zu sein, weil es nicht möglich ist, auf Inhalte des Moduls dann auch zuzugreifen. (Die vergleichenden Aufrufe, ausprobiert mit Python direkt, haben jeweils anstandslos geklappt.) :-(

Beim Versuch, eine Funktion aufzurufen, ergibt sich:

Code: Alles auswählen

com.sun.star.uno.RuntimeException: Error during invoking function gehzurAuswertung in module .../Scripts/python/Auswertung01g.py (<class 'AttributeError'>: 'module' object has no attribute 'machAuswertung'
  File "...\LibreOffice 5\program\pythonscript.py", line 870, in invoke
    ret = self.func( *args )
  File "...\Scripts\python\Auswertung01g.py", line 19, in gehzurAuswertung
    ausw01a.machAuswertung()
)
Der Versuch, auf eine Funktion innerhalb einer Klasse zuzugreifen, ergibt die Fehlermeldung:

Code: Alles auswählen

com.sun.star.uno.RuntimeException: Error during invoking function gehzurAuswertung in module .../Scripts/python/Auswertung01g.py (<class 'TypeError'>: machAuswertung() takes 0 positional arguments but 1 was given
  File "...\LibreOffice 5\program\pythonscript.py", line 870, in invoke
    ret = self.func( *args )
  File "...\Scripts\python\Auswertung01g.py", line 21, in gehzurAuswertung
    aw.machAuswertung()
)
Angesichts der Tatsache, daß völlig korrekt 'zitiert' wird: "machAuswertung()", also einer Anweisung ohne jedes weitere Argument, ist das in meinen Augen ziemlich absurd (oder wird da so etwas wie ein verstecktes 'self' aktiv?)... aber die Meldung scheint LibreOffice sehr zu mögen :-( . Wenn ich versuche, einen Befehl aus einem selbstgeschriebenen Programm an einen Button zu binden, kommt sie exakt auch so. Rufe ich den Befehl stattdessen über das Menu auf (also Extras -> Makros -> Makro ausführen), funktioniert er. Ist zwar für mich in keiner Weise plausibel nachvollziehbar, aber wenigstens zuverlässig reproduzierbar...
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

Code: Alles auswählen

machAuswertung() takes 0 positional arguments but 1 was given
Falls du eine Funktion per Button aufrufst wird dieser ""Button"" als Argument an die aufgerufene Funktion durchgereicht, du musst daher zumindest in der Funktionssignatur ein optionales Argument eintragen:

Code: Alles auswählen


def machAuswertung( *event ):
    …
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

Danke für die geduldigen Erklärungen!
Ich habe zugegebenermaßen keine Ahnung, was *event bedeutet und was es da macht (so weit beherrsche ich Python noch nicht), aber es sorgt zumindest dafür, daß ich das Makro sowohl über einen Button wie auch über "Makro ausführen" starten kann.

Allerdings nehmen die import-Probleme immer noch kein Ende :-( . LibreOffice kann offenbar weder in der Modul-Datei einen import eines andern Standard-Moduls von Python durchführen, noch genügt der import innerhalb der zuerst aufgerufenen Datei, damit die Standard-Befehle innerhalb der Modul-Datei verfügbar wären. Ich habe versucht, Daten mit "copy.deepcopy()" zu kopieren. Nehme ich den 'gewöhnlichen' Weg von "import copy" am Dateianfang der direkt aufgerufenen oder der Modul-Datei, bekomme ich jeweils den Fehler:

Code: Alles auswählen

com.sun.star.uno.RuntimeException: Error during invoking function gehzurAuswertung in module 
.../LibreOffice/4/user/Scripts/python/Auswertung01h.py (<class 'NameError'>: global name 'copy' is not defined
  File "...\LibreOffice 5\program\pythonscript.py", line 870, in invoke
    ret = self.func( *args )
  File "...\LibreOffice\4\user\Scripts\python\Auswertung01h.py", line 12, in gehzurAuswertung
    ausw01c.macheAuswertung(desktop)
  File "...\LibreOffice\4\user\Scripts\python\pythonpath\ausw01c.py", line 59, in macheAuswertung
    gregidict[grxname] = {"Einordnung": copy.deepcopy(grxlist)}
)
Auch mit "from copy import deepcopy" ist die Fehlermeldung praktisch dieselbe. Selbst "import copy as copy" hat keine Lösung dargestellt. Ohne den Aufruf von Standard-Modulen wird das Programmierer-Leben allerdings hart...

Sind die Probleme in OpenOffice eigentlich dieselben, oder läuft das Marko-Schreiben da flüssiger? (Es scheint ja zumindest in den zu verwenden Pfaden Unterschiede zu geben, sofern die Angabe aus dem OpenOffice-Wiki noch korrekt ist, und könnte also auch noch mehr Änderungen geben, die das eine oder andere Programm vorziehen lassen.)
BlackJack

@merlem: Importe beziehen sich immer nur auf das Modul in dem sie durchgeführt werden. Wenn Du also das `copy`-Modul in einem Modul verwenden möchtest, musst Du das *in dem* Modul importieren. Also in diesem Fall in `ausw01c`.

Edit: ``def mach_auswertung(*event):`` ist übrigens IMHO nicht gut, weil verwirrend, denn `event` ist hier dann ja eine Sequenz und kein einzelnes Argument. Der Name ist irreführend. Also entweder ``def mach_auswertung(event=None):`` wenn tatsächlich nur ein optionales Ereignisobjekt erwartet wird, oder ``def mach_auswertung(*args):`` beziehungsweise ``def mach_auswertung(*arguments):`` wenn man beliebig viele Argumente erwartet. Ich persönlich würde den Namen dann noch mit einem Unterstrich anfangen lassen wenn das Argument nicht verwendet wird. Das ist zwar nicht nur meine Konvention, aber auf der anderen Seite ist sie auch nicht *soo* weit verbreitet. Ein einzelner Unterstrich wenn man gar keinen Namen haben möchte, dagegen schon wieder mehr.
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

Dein gezeigter traceback würde passen zu:

Code: Alles auswählen

from copy import deepcopy


am Anfang des moduls… natürlich ist in dem Modul nur `deepcopy` im namespace, kann es sein das dir noch essentielle Grundlagen fehlen, neben den kleinen Spezialfällen die in|aus Libreoffice heraus möglich sind?
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

BlackJack hat geschrieben:@merlem: Importe beziehen sich immer nur auf das Modul in dem sie durchgeführt werden. Wenn Du also das `copy`-Modul in einem Modul verwenden möchtest, musst Du das *in dem* Modul importieren. Also in diesem Fall in `ausw01c`.
In diesem Fall allerdings hilft das nicht. Den import im sozusagen 'übergeordneten' Modul zu probieren war mehr ein Abchecken aller Möglichkeiten, nachdem der für Python normal (also ohne LO) funktionierende Weg Fehlermeldungen produziert hat. Kann ja sein, daß da noch mehr Sachen anders sind - was ja bei den Pfaden auch schon so war, und ich habe den Eindruck, daß das bei weitem noch nicht alles ist. (Ich kann LO beispielsweise per Python 'Gespenster sehen lassen', was mit Python allein so nie funktioniert... :-o aber ich habe noch keinen hübschen Demo-Code. Muß ich irgendwann mal präparieren...)
BlackJack hat geschrieben: Edit: Also entweder ``def mach_auswertung(event=None):`` wenn tatsächlich nur ein optionales Ereignisobjekt erwartet wird, oder ``def mach_auswertung(*args):`` beziehungsweise ``def mach_auswertung(*arguments):``
Ich habe keine rechte Ahnung, was LO da 'erwartet'. Nur pure Existenz?

EDIT:
Wenn ich von *event zu *_args wechsele, verschwindet der Importfehler. Entweder war der auch noch ein 'Gespenst' (ich habe parallel den Dateinnamen geändert, das 'bannt' solche Gespenster schon mal), oder es macht noch irgendeinen Unterschied über die pure Benennung hinaus?
/EDIT
karolus hat geschrieben: Dein gezeigter traceback würde passen zu:

Code: Alles auswählen

from copy import deepcopy
Was aber nicht im code steht. Im code steht, wie es sich 'gehören' würde, wenn es um Python geht, bei dem entsprechenden Aufruf mit 'copy.' zu Beginn 'import copy'. Bei der Änderung zu 'from' wird auch das 'copy.' gelöscht.

Mit "from copy import deepcopy":

Code: Alles auswählen

com.sun.star.uno.RuntimeException: Error during invoking function gehzurAuswertung in module file:.../LibreOffice/4/user/Scripts/python/Auswertung01h.py (<class 'NameError'>: global name 'deepcopy' is not defined
  File "...\LibreOffice 5\program\pythonscript.py", line 870, in invoke
    ret = self.func( *args )
  File "...\LibreOffice\4\user\Scripts\python\Auswertung01h.py", line 10, in gehzurAuswertung
    ausw01c2.macheAuswertung(desktop)
  File "...\LibreOffice\4\user\Scripts\python\pythonpath\ausw01c2.py", line 57, in macheAuswertung
    gregidict[grxname] = {"Einordnung": deepcopy(grxlist)}
)
Und natürlich kann es immer sein, daß mir noch Grundlagen fehlen. Aber ich weiß, wie ich die Sache in Python allein zum Laufen gebracht habe, und Python allein produziert eine solche Fehlermeldung nicht, wenn ich am Anfang der Datei 'import copy' stehen habe. LO schon.
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo
Ich habe keine rechte Ahnung, was LO da 'erwartet'. Nur pure Existenz?
LO erwartet da nichts sondern reicht (im weitesten Sinn) das Object als Argument durch über welches die Funktion aufgerufen wird.
das musst du dann in der Funktionssignatur berücksichtigen.
BlackJack

@merlem: Also wenn am Anfang vom Modul ``from copy import deepcopy`` steht und *das* bei der Ausführung zu keiner Fehlermeldung führt, dann kann es nicht sein, dass später im Modul der Aufruf von `deepcopy()` zu einem NameError führt. Es sei denn man hat dazwischen noch ein ``del deepcopy`` oder etwas Vergleichbares gemacht um den Namen explizit wieder zu löschen.
merlem
User
Beiträge: 8
Registriert: Sonntag 22. Januar 2017, 17:14

LibreOffice hat da offenbar das Unmögliche aber eben doch möglich gemacht.
Sonst hätte ich es ja auch kaum im Forum als Frage einbringen müssen, oder?
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

merlem hat geschrieben:LibreOffice hat da offenbar das Unmögliche aber eben doch möglich gemacht.
Sonst hätte ich es ja auch kaum im Forum als Frage einbringen müssen, oder?
Um das verifizieren zu können, müsstest du aber mal den ganzen Quelltext dazu zeigen, und nicht nur Tracebacks die nicht richtig zuzuordnen sind.
Antworten