SAP - ABAP und Python

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
Stefan Schnell
User
Beiträge: 5
Registriert: Mittwoch 27. August 2014, 08:41

Hallo zusammen,

ich habe im SAP Community Network (SCN) eine Artikelreihe zur Nutzung von SAP - ABAP und Python veröffentlicht.

1. Der Verbindungsaufbau
2. SAP-Funktionen aufrufen
3. ABAP-Programm mit Python erstellen und ausführen
4. Lesen von SAP-Tabellen
5. Python-Funktion aus ABAP nutzen - Python als SAP Server Application

Viel Spaß beim Kombinieren von SAP - ABAP und Python.

Beste Grüße
Stefan
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Stefan Schnell: Wie bindest Du denn das Modul »sapnwrfc« ein? Mit exec macht man sowas nicht, dafür gibt es import! Vergiß ganz schnell, dass es exec überhaupt gibt. Die Einrücktiefe ist 4 Leerzeichen, und nicht 2. «del« ist in den meisten Fällen unsinnig, so auch in Deinen Programmen. Vergleiche mit None macht man per »is None« bzw. »is not None«. Auch wenn die C-Api seltsame Namen vorgibt, darf man in Python statt »hDesc« auch sprechender Namen wie »sap_handle« nehmen.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Hallo,
willkommen im Forum, lass Dich vom Tonfall nicht abschrecken, so ist das hier.

Ich vermute mal Du hast das Tutorial so gemacht, wie Du Dir eins gewünscht hättest, als Du mit Python und SAP angefangen hast. Das heißt Du hast damit das beste (oder einzige) Tutorial auf dem Markt, Glückwunsch!

Das ganze sieht aus, als hättest Du den Programmcode von einer anderen Sprache in Python übersetzt, ist das richtig?
Für den Anfang ist es dabei OK möglichst viel so zu lassen, wie es im Ursprungscode war (das mache ich auch so, wenn ich Fortran Programme in Python oder C++ neuschreibe). Insbesondere die Variablennamen lasse ich original, das hilft extrem bei der Fehlersuche.

Gibt es einen Grund für

Code: Alles auswählen

#-Include---------------------------------------------------------------
FileName = "sapnwrfc.py"
exec(compile(open(FileName).read(), FileName, "exec"))
Folgendes wäre mehr Pythonic

Code: Alles auswählen

import sapnwrfc
Man braucht dann noch nicht mal zu kommentieren, dass man was importiert, denn es steht ja das Kommando "import" da.

Wenn die Code Vorlage Java ist, dann hilft Dir folgendes vielleicht weiter:

Code: Alles auswählen

Java           Python
 ==               is
 =!               is not
equals            ==
a fool with a tool is still a fool, www.magben.de, YouTube
BlackJack

@MagBen: Die Vergleichstabelle ist ohne zusätzliche Einschränkungen Falsch:

Code: Alles auswählen

In [17]: a, b, c
Out[17]: (10000, 10000, 10000)

In [18]: a is b
Out[18]: True

In [19]: a is c
Out[19]: False

In [20]: a == c
Out[20]: True
@Stefan Schnell: Das Python sieht nicht wirklich nach Python aus. Dazu werden zu viele Konventionen verletzt und auch die Sprache gar nicht richtig ausgenutzt.

Es werden zu viele Zwischenergebnisse unnötigerweise an Namen gebunden. Ganz allgemein ist der ganze Code auf Modulebene der in jedes Beispiel kopiert wird schlechter Programmierstil. Da würde man sinnvolle Funktionen und Klassen erwarten. Die Funktionen dann auch auf Modulebene und nicht auf dem SAP-Objekt.

Fehlerbehandlung wird in Python mit Ausnahmen gemacht und nicht mit speziellen Rückgabewerten. Überhaupt ist die Integration in Python fast nicht vorhanden.

So ein `RFC_CONNECTION_PARAMETER`-Array scheint ja eine Art Wörterbuch zu sein, da würde ich also von einer API in Python erwarten das ich eine `open_connection()` bekommen bei der ich Schlüsselwort-Argumente übergeben kann, die dann für den Funktionsaufruf von der DLL für mich in ein so ein Array umgewandelt werden und ich mich da nicht selber drum kümmern muss. Und das die Funktion eine Ausnahme auslöst wenn die Verbindung nicht klappt. Und in dieser Ausnahme sollten dann die Informationen aus der `RFC_ERROR_INFO`-Struktur stecken. Eben wie man Python so benutzt. Wenn Python nur als Syntax für die C-API benutzt wird und die Schnittstelle zu ABAP wie ein Fremdkörper aussieht, kann man eigentlich gleich C nehmen. Python nimmt man ja weil's schöner werden soll. :-)

Mal die ersten drei Artikel angeschaut würde ich Python-Code erwarten der eher so aussieht:

Code: Alles auswählen

import sap_rfc


def main():
    with sap_rfc.open_connection(
        ASHOST='ABAP', SYSNR='00', CLIENT='001', USER='BCUSER', PASSWD='minisap'
    ) as connection:

        # Variante 1:
        with connection.get_function('RFC_PING') as ping_function:
            if ping_function() == sap_rfc.OK:
                print('Ping successful.')
            else:
                print('Ping not successful.')

        # Variante 2:
        if connection.ping().return_code == sap_rfc.OK:
            print('Ping successful.')
        else:
            print('Ping not successful.')

        with connection.get_function('RFC_SYSTEM_INFO') as get_system_info:
            info = get_system_info()
            print(info.RFCHOST)
            print(info.RFCSYSID)
            print(info.RFCDBHOST)
            print(info.RFCDBSYS)

        with connection.get_function(
            'RFC_ABAP_INSTALL_AND_RUN'
        ) as install_and_run:
            program_table = install_and_run.get_table('PROGRAM')
            program_table.set_column(
                'LINE',
                [
                    'Report zTest Line-Size 256.',
                    "Write: 'Hello World from'.",
                    "Write: sy-sysid.",
                ]
            )
            install_and_run()
            result = ''.join(
                install_and_run.get_table('WRITES').iter_column('WRITES')
            )
            print result
Funktioniert `RfcGetVersion()` überhaupt wie im Artikel gezeigt? Ich sehe nicht wie da auf magische Weise die Versionsinformationen in die `c_ulong`-Objekte kommen sollen wenn man beim Aufruf keine Zeiger übergibt sondern die Werte selbst!?

Wie kommt man auf die Idee eine Liste mit einer leeren literalen Liste zu erstellen um dann in den Folgezeilen einzelne literale Elemente mit `append()` hinzuzufügen? Das ist Python und nicht Java. ;-)
Stefan Schnell
User
Beiträge: 5
Registriert: Mittwoch 27. August 2014, 08:41

Hallo zusammen,

erstmal Danke für Eure Hinweise.

Ich will gerne gestehen, dass ich von Python, bis zu diesem Projekt, nicht die leiseste Ahnung hatte. :roll:
Primär stand für mich die Anbindung von SAP im Vordergrund, mit der Nutzung einiger Möglichkeiten. Wie MagBen es vermutet, so ist es auch. Die Python-Sourcen sind aus einer anderen Sprache "übersetzt" worden. Die dort vorhandene Denkweise und Struktur habe ich übernommen und damit eben die Python-Konventionen eher ungewöhnlich gebeugt. :wink:
Ich nehme jetzt mal diesen Ansatz als Basis und arbeite Eure Vorschläge ein - der Code von BlackJack zeigt ja die mögliche Einfachheit.

Mit exec wollte ich ein simples Include nachbilden, also das schlichte Einlesen einer Datei mit der Möglichkeit der Nutzung ihres Inhaltes.

Wie zu sehen ist, habe ich bezüglich des Verständnisses der Python-Spezifika und -Philosophie noch einen erheblichen Nachholbedarf, also mache ich mich auf den Weg - deshalb bin ich ja auch hier.

Beste Grüße
Stefan
Antworten