Funktion interpretiert Argument "falsch"/garnicht

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
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

Hallo zusammen,

ich bin Python-Neuling und hab vor kurzem erst angefangen, mich in die Sprache einzuarbeiten. Ich möchte durch ein Python-Script ein Programm (ControlDesk), das einen Hardware-in-the-Loop-Simulator steuert, automatisieren. Dazu habe ich mir einen mitgelieferten Demofile genommen und will ihn für meine Zwecke abändern (Interpretation klappt dank der jetzigen Grundlagen und C++-Kenntnisse ganz gut :) Das Original-Demoskript funktioniert auch einwandfrei).

Es geht darum, einen Parameter zu verändern, bspw. eine 0-1-Taktung an einem der Eingänge des Simulators zu realisieren. Hierzu kann man in ControlDesk den sog. ParameterEditor() mit dazugehörigen Methoden nutzen, der dann die Parameter ins Programm "einpflegt".

Hier ist der Code, den ich gerade ausführen will:

Code: Alles auswählen

#ControlDesk-Spezifisches
from cdautomationlib import (.....)
import cdacon
from dSPACEDemoUtilities import (.....)

import os 
import sys  
import string 

WorkingDir = os.path.dirname(sys.argv[0])
if os.path.isdir(WorkingDir) == 0:
    WorkingDir = os.getcwd()

SavePath1 = os.path.normpath(WorkingDir + "\\SavePAR1")
PARFile1 = SavePath1 + "\\PARFile1.par"
print PARFile1        
# Das funktioniert, Pfad wird ausgegeben.                                 

PGain = "Model Root/DAC/Channel/Value"  
print PGain     
# Auch dieser Pfad wird ausgegeben                                    

if not os.path.exists(SavePath1):
    os.mkdir(SavePath1)
else:
    if os.path.exists(PARFile1):
        os.remove(PARFile1)

ParameterEditor().Generate(SDFFile, PARFile1, cdacon.false)
print "Successfully generated"
# Bis hierhin keine Probleme

ValueP = ParameterEditor().ReadParameter(PARFile1, PGain)   #Hier tritt der Fehler auf
print ValueP
print "Loop finished"
Bei ReadParameter (die man leider nicht einsehen kann und zu der keine Dokumentation vorliegt) kommt dann diese Fehlermeldung:
Traceback (most recent call last):
File "<string>", line 937, in _InternalRunScript
File "<string>", line 889, in _DoRunScript
File "D:\HardwareInTheLoop\YConverter HiL\Version Office\AutoScript.py", line 241, in <module>
ValueP = ParameterEditor().ReadParameter(PARFile1, PGain)
File "dSPACE Internal Module ControlDeskAutomation:cdautomationlib.py", line 908, in ReadParameter
File "dSPACE Internal Module ControlDeskAutomation:hierarchybrowsercomponent.py", line 80, in ReadParameter
File "C:\Program Files (x86)\Common Files\dSPACE\Python25\lib\site-packages\win32com\client\__init__.py", line 493, in _ApplyTypes_
dispid, 0, wFlags, retType, argTypes, *args),
ComClass "HIERAR~3"
Error : Schwerwiegender Fehler
Description : Parameter set ':\HardwareInTheLoop\(...)\SavePAR1\PARFile1.pa' not found
com_error: Ausnahmefehler aufgetreten.
Am Eigenartigsten erscheint mir dabei, dass ReadParameter offenbar den ersten und letzten Character abschneidet. Meine fruchtlosen Lösungsansätze bisher waren:
- ausführlichere Erweiterung der Adressierung:
ControlDesk arbeitet mit "Experimenten", die alle Unterordner, Variablen und ausführbare Simulationen enthalten und dem .py-file übergeordnet sind. Wir hatten die bestehenden Experiment-Deklarationen aus dem Demofile zunächst auskommentiert, um den Code übersichtlich zu halten. Ich habe alle Funktionen, die auch nur entfernt mit Adressen zu tun haben könnten, einzeln sowie in Kombination rein- und wieder rausgenommen.
- PARFile1.par manuell erstellt
- sämtliche Adressen sowohl durch Funktionsaufrufe "holen lassen" als auch explizit handgeschrieben
- ... abwechselnd mit doppelten und einfachen Backslashes und Anführungszeichen
- die PARFile1-Adresse mit einem Leerzeichen je vorne und hinten manipuliert
- einen Kollegen mit jahrelanger Python-Erfahrung gefragt, dem leider auch nichts einfiel.

Beim englischen Python-Forum habe ich einen Hinweis auf sys.argv[0] gefunden, das wohl einen derartigen Fehler produzieren kann (in dem konkreten Beispiel ging es um einen Server, der nicht erkannt wurde), falls es den Wert 1 hat. Das hat es bei mir. Aber ich weiß nicht, wie ich diesem Skript noch ein Argument übergeben sollte - und welches, und wozu? (Anmerkung hierzu: ich rufe die Main nicht auf, sondern lasse das ganze sozusagen "roh" durchlaufen. Ohne Funktionsaufruf.) Ich hab mir jedenfalls den ganzen Tag den Kopf zerbrochen und bin so langsam fertig mit den Nerven.

Das kann doch nicht so schwierig sein - übersehe ich vielleicht was? Vielleicht hat jemand eine Idee...

Viele Grüße

Ragen
BlackJack

@Ragen: Also wenn ConrolDesk an der Stelle tatsächlich die Zeichen abschneiden sollte, dann ist der Fehler eher in der Software zu suchen. Kannst ja mal zum Testen bei dem Dateinamen bei der Übergabe vorne und hinten ein Zeichen hinzuzufügen. Wenn ConrolDesk die entfernt müsste ja der passende Dateiname übrigbleiben.

Der Rückgabewert von `os.path.isdir()` sollte ein Wahrheitswert sein, da ist es sehr eigenartig den mit einer Zahl zu vergleichen. Das ist zwar möglich weil `bool` eine Unterklasse von `int` ist, aber ``if a_bool_value:`` oder ``if not a_bool_value:`` ist weniger verwirrend.

Pfade sollte man mit `os.path.join()` zusammensetzen.

Was sollen die 1en am Ende einiger Namen? Bitte nicht anfangen Namen zu nummerieren, schon gar nicht präventiv.
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

Guten Morgen @Blackjack!

Wenn man vorne und hinten ein Zeichen hinzufügt, kommt tatsächlich der richtige Dateipfad raus - die Fehlermeldung bleibt aber in genau dieser Form bestehen. Und leider findet sich im entsprechenden Ordner auch keine Datei PARFile1. (Die Zahlen an den Dateinamen hab ich aus der Demo übernommen. Es gab nur 1 und 2 zur Unterscheidung, wird glaub ich daher kommen, dass da ein Parametersatz verändert bzw. durch einen neuen ersetzt wird.)
Der Rückgabewert von `os.path.isdir()`...
Verstehe, was du meinst. Es ist wohl die präzisere Ausdrucksweise, verwirrt mich persönlich aber mehr ;)
Pfade sollte man mit `os.path.join()` zusammensetzen.
Interpretiert werden sie aber auch mit '+' richtig, was sich z.B. bei "print PGain" zeigt. Obendrein kannte ich diesen bzw. diese zwei os-Befehle garnicht. Danke, wieder was gelernt! ^^

Wenn ich mir das so angucke, liegt es vielleicht auch an .Generate(...), das keine richtige Datei erzeugt (und seinerseits auch nicht einsehbar ist). :?
BlackJack

@Ragen: Deine Verwirrung verwirrt mich. `os.path.isdir()` gibt einen Wert vom Typ `bool` zurück, also `True` oder `False`. Und Du vergleichst den dann mit einem Wert vom Typ `int`, nur um dabei wieder einen Wert vom Typ `bool` heraus zu bekommen der dann von dem ``if`` verwendet wird:

Code: Alles auswählen

n [12]: os.path.isdir('test.c')
Out[12]: False

In [13]: False == 0
Out[13]: True

In [14]: os.path.isdir('test.c') == 0
Out[14]: True

In [15]: not os.path.isdir('test.c')
Out[15]: True
Wenn ich nicht durch C vorbelastet wäre, würden mich [13] und [14] erst einmal ohne Ende verwirren. :-)

Apropos verwirrt: Wenn `Generate()` die Datei nicht erzeugt, dann ist doch klar das `ReadParameter()` die nicht finden kann‽
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

`os.path.isdir()` gibt einen Wert vom Typ `bool` zurück, also `True` oder `False`. Und Du vergleichst den dann mit einem Wert vom Typ `int`, nur um dabei wieder einen Wert vom Typ `bool` heraus zu bekommen der dann von dem ``if`` verwendet wird
Achso, jetzt verstehe ich bei genauerem Hinsehen, was du wirklich meintest.^^ Dieser Vergleich mit '== 0' ist tatsächlich etwas überflüssig, ja, da gebe ich dir recht. Pro [15] ;) Hab ich aber auch nicht geschrieben, das hat sich jemand bei dSpace einfallen lassen. Ist mir bisher noch garnicht aufgefallen.

Naja, meine naive Annahme war, dass, wenn die Zeile nach 'Generate()' ausgeführt wird, dass Generate() selbst dann ordnungsgemäß funktioniert hat, und irgendeinen Fehler geworfen hätte, wenn keine Datei erstellt werden konnte.
BlackJack

@Ragen: Die Annahme finde ich eigentlich gar nicht naiv. Vielleicht weil ich nicht naiv sein will, denn ich wäre da auch von ausgegangen das sich eine Funktion/Methode mit einer Ausnahme beschwert wenn sie ihre Arbeit nicht machen konnte.

Gibt die Methode vielleicht einen Fehlercode zurück? Was sind denn diese `ParameterEditor`-Objekte? Kann es vielleicht sein, dass die „hinter sich aufräumen” und die Datei zwar erstellt, dann aber wieder gelöscht wird wenn die Speicherbereinigung das Objekt abräumt? Oder gibt es auf diesen Objekten vielleicht ein Attribut oder eine Methode um zu prüfen ob `Generate()` erfolgreich war? Was sagt denn die Dokumentation zu dem Ganzen? Fragen über Fragen. :-)
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

Gibt die Methode vielleicht einen Fehlercode zurück?
Der Rückgabetyp ist boolesch und es kommt True zurück.
wenn die Speicherbereinigung das Objekt abräumt
Es gibt eine Art Doku, aber die bezieht sich nur auf die Nutzung des Tools (über die GUI). So wie ich das verstehe, wird vielleicht beim Öffnen des aktuellen Experiments oder beim Importieren aus der cdautomationlib ein einziges ParameterEditor-Objekt erstellt. Wann genau kann ich nur raten, aber beim Importieren erscheint mir sinnvoll. Außerdem rufe ich das selbe Objekt danach nochmal auf (die ganze Demo dreht sich um seine verschiedenen Funktionen), also wäre zwischendurch löschen nicht so praktisch.

Ob es da noch überprüfende Methoden gibt, könnte man mal wehrifizieren - führt mich aber jetzt zu weit von meinem eigentlichen Thema weg. Und nicht zu vergessen: der unmodifizierte Demofile läuft ja! Wenn mir mein Kollege das Dongle wiedergibt, probiere ich es einfach mal damit, die unmodifizierte Demo Stück für Stück auszukommentieren. *seufz*
BlackJack

@Ragen: Es gibt keine API-Dokumentation zu den Modulen? Wer verwendet denn so ein Produkt‽ Sind die Objekte wenigstens selbst dokumentiert, also kannst Du eine Python-Shell aufmachen, den Kram importieren und `help()` zum Beispiel mit dem Modul oder dem `ParameterEditor`-Objekt aufrufen? Ohne anderweitige Dokumentation bleibt einem ja gar nichts anderes übrigen als eine gute Python-Shell wie IPython oder bpython her zu nehmen und das Ganze „live” zu erforschen. Einer der Vorteile von Python, das man Objekte nach ihren Attributen und an die Objekte gehängte Dokumentation fragen kann. :-)

So wie der Code aussieht werden *zwei* `ParameterEditor`-Objekte erstellt — und sind beide auch gleich wieder frei für den Abschuss durch die automatische Speicherverwaltung. Es sei denn `ParameterEditor` ist gar kein Datentyp sondern eine Funktion die ein entsprechendes Objekt zurück gibt. Eigentlich sollte das Objekt aber durch den Aufruf erstellt werden. Beim importieren würde es nur Sinn machen wenn es ein Singleton ist. Auf jeden Fall würde ich ohne eine Vergewisserung nicht davon ausgehen, dass Du die beiden Methoden tatsächlich auf dem selben Objekt aufrufst.
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

Ok - dass Python Objekte zum Reden bringen kann, wusste ich auch nicht. Mit help(...), ja? :)

Entweder suche ich nach den völlig falschen Begriffen, oder so etwas wie eine detaillierte Dokumentation über die Funktionsweise dieser Tools existiert nicht. Firmenstrategie...?
BlackJack

@Ragen: `help()` um DocStrings abzufragen sofern vorhanden und `dir()` um die Attribute von Objekten abzufragen. Dran denken das sowohl Module als auch Klassen in Python Objekte sind.

Etwas komfortabler ist dann zum Beispiel IPython. Die Python-Shell hat Autovervollständigung per Tabulatortaste für Attribute auf einem Objekt welches man direkt referenzieren kann und statt `help()` kann man einfach ein Fragezeichen hinter dem Objekt setzen für das man die „live”-Dokumentation sehen möchte. Bei Objekten die in Python geschrieben sind und wo der Quelltext vorliegt bekommt man mit zwei Fragezeichen diesen angezeigt.
Ragen
User
Beiträge: 6
Registriert: Mittwoch 11. Dezember 2013, 15:23

Also, es gibt eine Doku:
| Generate(self, TrcFilename, ParFilename, Handcoded=0)
| Generates a PAR-file from a loaded TRC-file.
| Syntax : Ret = OBJ.Generate(TrcFilename, ParFilename [, Handcoded = 0])
|
| Parameters : TrcFilename - string - Filename of the TRC-file.
| ParFilename - string - Filename of the generated PAR-file.
| Handcoded - boolean - For handcoded models. To consider a filter rule while generating the PAR-file.
|
| Return Value: Ret - boolean - TRUE on success.
|
| Exceptions : TypeError - Parameter has the wrong type.
| TypeError - The file specified by the filename does not exist.
Allerdings bin ich über ein paar Umwege auf das Einbinden des "Experiments" zurückgekommen und ich glaube, dass der Fehler tatsächlich da zu suchen ist, auch wenn es mit den Tools und Funktionen selbst nichts zu tun hat. Ich benutze ControlDesk 4.x, die Demo scheint aber für 3.x geschrieben worden zu sein und da gibt es Unstimmigkeiten im Dateiformat. Ich gucke jetzt gerade, wie man das ummünzen kann, und hoffe sehr, dass sich das Problem dann von alleine löst.

Gruß
Ragen
Antworten