Python2-Programm soll Python3-Script aufrufen --> Fehler

Probleme bei der Installation?
Antworten
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Hallo zusammen,

ich habe ein kleines Script, welches über die serielle Schnitstelle mit einem Arduino kommuniziert und diesem Anweisungen bzgl. einer Motordrehzahl gibt. Die entsprechende Drehzahl wird als Argument dem Script übergeben.
Das entsprechende Script schaut so aus und ist in Python3-konform:

Code: Alles auswählen

#!/usr/bin/env python3
import sys
import time
import serial
 
PORT = '/dev/tty.usbmodemFA131'
 
with serial.Serial(PORT, 9600) as arduino:
    time.sleep(2)
    arduino.write(sys.argv[1].encode('ASCII'))
    print(arduino.readline())
Bei Aufruf aus dem Terminal funktioniert alles bestens. Das Script funktioniert also :)

Nun will ich das Script aber nicht aus dem Terminal aufrufen, sondern per "Klick" aus einem anderen Programm heraus. Es handelt sich dabei um Artisan - eine Software zur Aufzeichnung von Röstvorgängen.
Artisan erlaubt es, Buttons zu definieren, welche per Klick externe Programme aufrufen. In meinem Fall eben das obige Script.
Artisan selbst ist in Python2 geschrieben.

Wenn ich nun einen der Buttons anklicke um mein Script aufzurufen, stürzt Python ab und im Terminal erscheint folgende Meldung:

Code: Alles auswählen

Last login: Wed Jul 13 07:21:46 on ttys000
Philipps-Air:~ philipp$ /Applications/Artisan.app/Contents/MacOS/Artisan ; exit;
Jul 13 07:22:20  Artisan[40170] <Notice>: /Applications/Artisan.app/Contents/Resources/lib/python2.7/site-packages.zip/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.
Jul 13 07:22:57  Artisan[40170] <Notice>: Fatal Python error: Py_Initialize: unable to load the file system codec
Jul 13 07:22:57  Artisan[40170] <Notice>: ImportError: No module named 'encodings'
Jul 13 07:22:57  Artisan[40170] <Notice>: 
Jul 13 07:22:57  Artisan[40170] <Notice>: Current thread 0x00007fff73660000 (most recent call first):
Wenn ich das richtig verstehe, wird versucht, das Script mit dem Python2- statt dem Python3-Interpreter zu starten, obwohl ich dies in der Shebang-Zeile explizit vorgebe? :K

Ich weiss, dass es definitiv möglich ist, Python-Scripte aus Artisan heraus zu starten, allerdings sind die mir bekannten Scripte ebenfalls in Python2 verfasst...

Gibt es grundsätzlich Probleme bei einer solchen Konstellation?

Gibt es Möglichkeiten dies zu umgehen, ohne das Script Python2-konform umzuschreiben?

Ich nutze MacOS 10.11.5 und habe Python 3.5.2 nachinstalliert.

Vielen Dank für eure Hilfe!

Philipp
BlackJack

@phischmi: Kann das Programm tatsächlich beliebige externe Programm starten? Oder hat das einen Python-Interpreter integriert und kann in dem Python-Skripte ausführen?
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Habe grad die Info bekommen, dass es einen Interpreter mit den benötigten Bibliotheken integriert hat :?
Gibt es denn dann eine Möglichkeit, mein Script trotzdem mit dem Python3-Interpreter zu starten und nicht den Umweg z.B. über ein Shell-Script zu gehen?
BlackJack

@phischmi: Du könntest ein Python 2-Skript schreiben dass dann Dein Python 3-Programm aufruft. Oder Du schreibst es in Python 2 um. So unterschiedlich sind die Sprachen ja nicht. Dann ist allerdings die Frage ob/wie Du das `serial`-Modul für das eingebettete Python installieren kannst.
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Danke!

Dann werde ich später etwas in dieser Form ausprobieren:

Code: Alles auswählen

subprocess.call("arduino.py " + sys.argv[1], shell=True)
Sollte genügen, oder?
BlackJack

@phischmi: Da ist eine Shell zu viel dazwischen. Für ``shell=True`` sollte man einen guten Grund haben.
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Ok, also

Code: Alles auswählen

import call from subprocess
call("arduino.py " + sys.argv[1])
Somit wird das Script mit dem in der Shebang-Zeile genannten Interpreter gestartet, ja?
Das ' 'shell=TRUE' ' macht also nur Sinn, wenn man z.B. auf Shell-spezifische Variablen zurück greifen will?

Hatte ich mir einfacher vorgestellt, aber was soll's - viel gerlent in den letzten Tagen :D
BlackJack

@phischmi: Nein, ohne Shell-Argument muss man eine Liste übergeben die wie `sys.argv` aufgebaut ist. Diese Liste kommt ja auch von einem Aufruf. ``shell=True`` braucht man nur wenn man auf Shell-Variablen zugreifen muss, oder andere Shell-Syntax, wobei man das meiste auch in Python ausdrücken kann. Zum Beispiel gibt es nicht wirklich viele Shell-Variablen. Das sind ja nur Variablen die tatsächlich nur innerhalb der Shell zur Verfügung stehen und keine allgemeinen Umgebungsvariablen.
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Ok, das war mir nicht bewusst.
Dann sollte es also richtig heissen

Code: Alles auswählen

import call from subprocess
call('./arduino.py', sys.argv[1])
Ich habe Snippets gefunden, welche als erstes Argument 'python3' übergeben, das dürfte in meinem Beispiel jedoch nicht nötig sein, aufgrund der Shebang-zeile im Script, oder?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@phischmi: Das erste Argument muß eine Liste sein!

Code: Alles auswählen

from subprocess import call
call(['./arduino.py', sys.argv[1]])
... wenn die Datei ausführbar ist, dann ist das explizite aufrufen von python3 nicht nötig.
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

So, habe u.a. den obigen Code grad eben ausprobiert - leider ohne Erfolg :(
Python stürzt weiterhin mit der Fehlermeldung aus meinem ersten Post ab...

Auch der Umweg über ein Shell-Script statt des zweiten Python-Scripts führt zu dem selben Ergebnis.

Alternativ habe ich mein eigentliches Script nun einmal Python2-konform umgeschrieben.

Code: Alles auswählen

#!/usr/bin/env python

import sys
import time
import serial

PORT = '/dev/tty.usbmodemFA131'

with serial.Serial(PORT, 9600) as arduino:
    time.sleep(2)
    arduino.write(sys.argv[1])
    print(arduino.readline())
    
Python stürzt dann zwar nicht mehr ab, im Ergebnis passiert jedoch auch nix. Im Terminal erscheint folgende Meldung (übrigens völlig unabhängig davon, ob ich das Script direkt oder über den Umweg eines zweiten Scripts aufrufen lasse).

Code: Alles auswählen

Jul 13 18:56:15  Artisan[40956] <Notice>: Traceback (most recent call last):
Jul 13 18:56:15  Artisan[40956] <Notice>:   File "/Users/philipp/arduino.py", line 5, in <module>
Jul 13 18:56:15  Artisan[40956] <Notice>:     import serial
Jul 13 18:56:15  Artisan[40956] <Notice>:   File "serial/__init__.pyo", line 13, in <module>
Jul 13 18:56:15  Artisan[40956] <Notice>:   File "serial/serialutil.pyo", line 10, in <module>
Jul 13 18:56:15  Artisan[40956] <Notice>:   File "io.pyo", line 51, in <module>
Jul 13 18:56:15  Artisan[40956] <Notice>: ImportError: dlopen(/Applications/Artisan.app/Contents/Resources/lib/python2.7/lib-dynload/_io.so, 2): Symbol not found: __PyCodecInfo_GetIncrementalDecoder
Jul 13 18:56:15  Artisan[40956] <Notice>:   Referenced from: /Applications/Artisan.app/Contents/Resources/lib/python2.7/lib-dynload/_io.so
Jul 13 18:56:15  Artisan[40956] <Notice>:   Expected in: flat namespace
Jul 13 18:56:15  Artisan[40956] <Notice>:  in /Applications/Artisan.app/Contents/Resources/lib/python2.7/lib-dynload/_io.so
Mit dieser Fehlermeldung kann ich jedoch gar nichts anfangen... :/
Direkt aus dem Terminal gestartet funktionieren übrigens alle Scripte.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@phischmi: StackOverflow meint, das sein ein OS-X Problem, das sich so auf der Kommandozeile lösen läßt:
[codebox=bash file=Unbenannt.bsh]hash -r python[/code]
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Danke für den Hinweis.
Habe ich grad probiert, hilft jedoch leider auch nicht... :?
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Wenn ich aus Artisan übrigens ein simples Script in der folgenden Form aufrufe, funktioniert dies.

Code: Alles auswählen

#!/usr/bin/env python
from sys import argv
print argv[1]
Das übergebene Argument wird ausgegeben.
Sobald ich jedoch versuche, auf libs zurück zu greifen, welche nicht im integrierten Interpreter enthalten sind, kommt es zu den o.g. Fehlermeldungen.
Es muss doch möglich sein, das externe Script explizit nicht mit dem internen Interpreter auszuführen :K
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Ich habe bei Stackoverflow grad noch einen interessanten Beitrag entdeckt.

http://stackoverflow.com/a/34861429

Kann es sein, dass ich mit meiner Shebang-Zeile

Code: Alles auswählen

#!/usr/bin/env python
immer auf den gecacheden Interpreter verweise?

Würde es evtl. einen Unterschied machen, hier explizit

Code: Alles auswählen

#!/usr/bin/python
anzugeben?

Kann grad nicht testen, daher meine Frage... :wink:
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Offensichtlich macht es keinen Unterschied... :(
Habe es soeben mit

Code: Alles auswählen

#!/usr/local/bin/python
ausprobiert und die Fehlermeldung bleibt die gleiche...

Was könnte ich noch ausprobieren? Welche Infos benötigt ihr ggf. noch um mir weiterhelfen zu können?
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Hallo nochmal,

für die, die es interessiert:

Den Fehler konnte ich nicht beseitigen, das Problem aber dennoch lösen :)

Ich arbeite nun mit ner simplen named Pipe.

Aus Artisan starte ich das folgende Script:

Code: Alles auswählen

#!/usr/bin/python

from sys import argv
import os
import time

path = "/tmp/my_program.fifo"

if not os.path.exists(path):
    os.mkfifo(path)

fifo = open(path, "w")
fifo.write(argv[1])
fifo.close()
Mit einem zweiten Script lese ich my_program.fifo nun aus und sende den Wert an den Arduino - funktioniert bestens :)

Danke für eure Bemühungen!

Philipp
phischmi
User
Beiträge: 34
Registriert: Dienstag 12. Juli 2016, 06:08

Ich habe nun übrigens auch eine Lösung für den Fehler gefunden :D
Ich habe die Datei _io.so aus dem dynload-Verzeichnis meiner vorinstallierten Python 2 Version in das Stamm-Verzeichniss meines Scriptes kopiert.
Es scheint offenbar Probleme mit der in Artisan enthaltenen Version zu geben...
Antworten