TRE über ctypes einbinden

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Samstag 17. März 2007, 21:40

Servus!

Da ja in Python 2.5 ctypes direkt eingebaut ist, habe ich mir gedacht, dass es doch mal interessant wäre, eine kleinere Library damit zu wrappen um la zu schauen wie sowas geht. Solche eine kleinere Library ist beispielsweise TRE. Sie zu wrappen ist insofern einfach, da sie universell verfügbar ist (sowohl unter Winows als auch Unices, in einigen Distributionen ist sie sogar mitgeliefert), und sie eine vergleichsweise simple API hat.
Ja, TRE hat zwar duchaus ein Python-Binding, aber das muss erst kompiliert werden. Und ja, ich weiß dass Python eine Regex-Engine hat. Aber so "schauen wir mal wie es geht"-Projekte müssen ja nicht unbedingt gleich wahnsinnig komplex werden. Außerdem bietet TRE einige Funktionen an, die SRE nicht bietet.

Aktueller Stand: Ich habe tre_version (*g*) gewrappt, regex_t gebaut und die regcomp()-Funktionen sollten ebenso wie regfree() korrekt aufrufbar sein. Man muss also noch die restlichen Funktionen und Konstanten wrappen und eine API bauen die der von SRE möglichs ähnlich ist und die die Funktionen robust verpackt (Beispielsweise ist es eine schlechte Idee regfree() zweimal mit den gleichen Argumenten aufzurufen, weil es sonst scheppert - Segfault).

Somit kann man dieses Projekt auch als kleines ctypes Howto betrachten.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 17. März 2007, 22:43

Leonidas hat geschrieben:Somit kann man dieses Projekt auch als kleines ctypes Howto betrachten.
Hi Leonidas!

Das finde ich super! Davon kann man dann sicherlich viel lernen. :)

Jemand könnte dann die damit gewonnenen Erfahrungen nutzen um z.B. eine plattformunabhängige MySQL-Schnittstelle zu schreiben, die nicht extra für jede Python-Version und jede Plattform kompiliert werden muss... (nur so als Zusatzidee)

Helfen kann ich dabei leider nicht. Ich werde nicht mal aus der API-Dokumentation zu TRE schlau. Da fehlt mir doch noch ein bischen Englisch dafür.

Was schlägst du zum Dokumentieren vor? WIKI?

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sonntag 18. März 2007, 00:26

gerold hat geschrieben:Jemand könnte dann die damit gewonnenen Erfahrungen nutzen um z.B. eine plattformunabhängige MySQL-Schnittstelle zu schreiben, die nicht extra für jede Python-Version und jede Plattform kompiliert werden muss... (nur so als Zusatzidee)
Stimmt, das wäre allerdings möglich. Habe ich schon erwähnt, dass es mit pg8000 so etwas schon für PostgreSQL gibt? Allerdings nutzt es kein ctypes um auf die libpq zuzugreifen sondern implementiert scheinbar das socket-Protokoll, welches PostgreSQL nutzt.
pg8000s Homepage hat geschrieben:pg8000's name comes from the belief that it is probably about the 8000th PostgreSQL interface for Python.
An sich ist es erstaunlich, dass es so viele Wrapper für Python gibt (ich glaube inzwischen sind es fünf). Wenn man von der Verbreitung ausgeht, sollte es ja für MySQL direkt noch mehr geben, aber das ist nicht der Fall. Sogar SQLite hat mehrere Wrapper.
gerold hat geschrieben:Helfen kann ich dabei leider nicht. Ich werde nicht mal aus der API-Dokumentation zu TRE schlau. Da fehlt mir doch noch ein bischen Englisch dafür.
Die API-Dokumentation ist gar nicht mal so übel, denn so ziemlich alles was nötig ist um diesen Wrapper zu schrieben steht in der API-Dokumentation und in der ``regex.h``. Wenn man weiß, wie man sowas mit ctypes implementiert, ist man schon auf dem richtigen Weg.
gerold hat geschrieben:Was schlägst du zum Dokumentieren vor? WIKI?
Entweder Wiki (aber im Moment habe ich keine Lust eines einzurichten) oder einfach Inline-Dokumentation. Vielleicht kann man ja auch ein paar Konzepte aus Literate haskell entnehmen.

Was ich gut brauchen könnte ist jemand mit etwas C-Erfahrung. Es ist zwar auch ohne zu schaffen, aber komplizierter.
Zuletzt geändert von Leonidas am Donnerstag 22. März 2007, 14:31, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Sonntag 18. März 2007, 01:28

Hi

Also ich hab ein wenig mit ctypes gearbeitet (nicht dll einbindung, nur structures und unions hab ich gebraucht) und c kann ich ein wenig.

Bin mir zurzeit eine implementation vom MTP (Media Transfer Protocol) zu schreiben, da muss ich c-structs via usb dem mp3player schicken. Den grössten Teil hab ich von der libmtp abgeschaut (C-Code).

Schreib doch einfach wo du Probleme hast, ich schaus mir an falls ich Zeit hab.

Gruss
BlackJack

Sonntag 18. März 2007, 09:58

@Leonidas: Für die Inlinedokumentation lohnt sich vielleicht ein Blick auf PyLit. Das ist noch recht jung und setzt auf ReStructured Text.

@rayo: Für binäre Datenstrukturen, vor allem im Bereich Protokolle, wo man auch mal auf einzelne Bitbereiche zugreifen möchte, ist Construct ganz nett.
Benutzeravatar
mq
User
Beiträge: 124
Registriert: Samstag 1. Januar 2005, 19:14

Sonntag 18. März 2007, 11:39

Klingt ganz nett, warum nicht? Und C-Kenntnisse hab ich auch.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sonntag 18. März 2007, 12:24

rayo hat geschrieben:Schreib doch einfach wo du Probleme hast, ich schaus mir an falls ich Zeit hab.
Danke fürs Angebot :)
BlackJack hat geschrieben:@Leonidas: Für die Inlinedokumentation lohnt sich vielleicht ein Blick auf PyLit. Das ist noch recht jung und setzt auf ReStructured Text.
Wow, das sieht interessant aus - ich hätte gar nicht gedacht, dass es sowas auch für Python gibt.
lumax hat geschrieben:Klingt ganz nett, warum nicht? Und C-Kenntnisse hab ich auch.
Fein :) Und über IRC bist du auch erreichbar. Wunderbar. Werd dich gleich mal anpingen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 20. März 2007, 00:39

Alzuweit bin ich nicht gekommen, weil ich es nicht auf die Reihe bekomme das vernünftig zum laufen zu bekommen.

Also, so sieht tre.py aus, das Testprogramm und die Ausgabe. Und natürlich die TRE API.

Natürlich stimmt die Ausgabe die da rauskommt so nicht - zumindest denke ich, dass da ganz andere Sachen rauskommen sollten. Ich denke man müsste hier noch einige Pointer einwerfen, aber ich komme einfach nicht drauf, wie das gehen soll. Kann mir jemand etwas Starthilfe geben?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Dienstag 20. März 2007, 06:49

Hi

Also laut der API brauchen alle Funktionen regex_t *preg als Parameter, du hast aber nur regex_t preg. Beim String übergeben weiss ich nicht ob er automatisch von Python Strings nach c_char_p wandelt.

Versuchs mal so:

Code: Alles auswählen

libtre.regcomp.argtypes = [POINTER(regex_t), c_char_p, c_int]

Code: Alles auswählen

from tre import *

preg = pointer(regex_t())

libtre.regcomp(preg, 'a', 0)

pmatch = pointer(regmatch_t())
nmatch = c_size_t()

print libtre.regexec(preg, ctypes.create_string_buffer('bcabca'), nmatch, pmatch, 0)

print nmatch
print type(pmatch), type(pmatch[0])
print pmatch[0].rm_so, pmatch[0].rm_eo
Am schluss bin ich mir auch nicht sicher ob pnmatch[0] geht, da pnmatch ja ein Pointer ist, aber da weiss ich grad keien Funktion.

Gruss
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 21. März 2007, 20:43

Hallo rayo, vielen Dank schonmal für deine Hilfe,
rayo hat geschrieben:Also laut der API brauchen alle Funktionen regex_t *preg als Parameter, du hast aber nur regex_t preg.
Stimmt. Das habe ich nun geändert. Interessanterweise hat ohne Pointer ``regfree()`` auch funktioniert (weil sonst segfalutet sie). Jetzt sind die Daten mit Pointern - allerdings hat sich bisher nichts am (fehlenden) Ergebnis geändert.
rayo hat geschrieben:Beim String übergeben weiss ich nicht ob er automatisch von Python Strings nach c_char_p wandelt.
Das sollte eigentlich gehen:
http://docs.python.org/lib/ctypes-calling-functions.html hat geschrieben:None, integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls. None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data (char * or wchar_t *).
Von daher bin ich optimistisch dasss das Problem nicht hier liegt.
rayo hat geschrieben:Am schluss bin ich mir auch nicht sicher ob pnmatch[0] geht, da pnmatch ja ein Pointer ist, aber da weiss ich grad keien Funktion.
Ich glaube das soll eben genau so gehen, zumindest laut dem Pointer-Artikel.

Aber ich glaube ich habe jetzt den Unterschied zwischen pointer und POINTER verstanden: POINTER erstellt einen neuen Typen und zwar die Pointer-Version des Angegebenen und pointer erstellt einen Pointer auf ein gegebenes Objekt. Richtig?

Die aktualisierten Dateien: Test-Datei (testet nun auch regfree) und Binding.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Mittwoch 21. März 2007, 23:34

Leonidas hat geschrieben:Aber ich glaube ich habe jetzt den Unterschied zwischen pointer und POINTER verstanden: POINTER erstellt einen neuen Typen und zwar die Pointer-Version des Angegebenen und pointer erstellt einen Pointer auf ein gegebenes Objekt. Richtig?
Genau so ist es.

Leider hab ich es bis jetzt noch nicht unter Windows zum laufen gebracht. Weiss nicht wie ich die dll laden kann, das was ich probiert habe ging nicht, kam immer dass er die DLL nicht gefunden hat.

Sonst würde ich auch ein wenig rumprobieren wo der Fehler ist.

Gruss

*edit*
Hast du mal getestet was von regcomp zurück kommt? 0 wenn Erfolgreich sonst die Fehlercodes die in der API beschrieben sind.

libtre.regcomp.restype = c_int einfach noch hinzufügen (ist glaubs sowieso Default)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 22. März 2007, 14:41

rayo hat geschrieben:Leider hab ich es bis jetzt noch nicht unter Windows zum laufen gebracht. Weiss nicht wie ich die dll laden kann, das was ich probiert habe ging nicht, kam immer dass er die DLL nicht gefunden hat.
Hast du das was hier beschrieben wird probiert? Oder vielleicht mit ``windll`` statt ``cdll`` laden? Es gibt auch hier noch einen Thread zu dem Thema (so nach dem Motto: ist die DLL im selben Ordner, etc).
rayo hat geschrieben:Hast du mal getestet was von regcomp zurück kommt? 0 wenn Erfolgreich sonst die Fehlercodes die in der API beschrieben sind.

libtre.regcomp.restype = c_int einfach noch hinzufügen (ist glaubs sowieso Default)
Ja, ich habe das im Tester mit print schon ausgeben lassen, es kommt Null raus. Das wundert mich ein wenig, denn interessanterweise kommt da auch Null raus, wenn da keinen Pointer übergebe. Und restype ist per Default schon c_int, von daher macht das keinen Unterschied.
Was ich auch noch nicht weiß ist, wie man die Konstanten auflöst. Ist aber im Moment noch nicht so wichtig, da ja keine Fehlercodes kommen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Samstag 24. März 2007, 11:30

Hi Leonidas

Habs nun hingekriegt, mir fehlte eine Abhängigkeit (hab ich übersehen beim ersten mal herunterladen). Wäre irgendwie schön, wenn dies eine bessere Fehlermeldung geben würde, weiss aber nicht ob das überhaupt möglich ist.


Ich hab sogar ein Match hingekriegt, nur leider musste ich den Prototyp von regexec rausnehmen, weil ich nicht weiss, wie ich einen Pointer auf einen Array, bei dem die Grösse ändern kann angebe.

Also mir ist da ein Licht aufgegangen:
Die Parameter nmatch, pmatch[] muss von uns Platz gemacht werden, damit er da rein seinen Match (nur einen) schreibt, wenn es Klammern hat (Subexpressions) braucht es mehr als einen, das hab ich noch nicht hingekriegt, da hat er mir immer 1 (glaubs NOMATCH) zurückgegeben.

Aber auf z.B. 5 pmatches konnte er zugreifen, weil er überall -1 reinschreibt, falls es kein Submatch gegeben hat.

Ich hab jetzt eine kleine Funktion geschrieben, dass den ganzen String wieder und wieder absucht, bis er keinen Match mehr gefunden hat (im Sinne von findall ;) )

tre.py (Windowsversion, reicht einfach die oberste Zeile zu ändern)

tre_tester.py
Leonidas hat geschrieben:Was ich auch noch nicht weiß ist, wie man die Konstanten auflöst. Ist aber im Moment noch nicht so wichtig, da ja keine Fehlercodes kommen.
Das musst du glaubs selber von der .h Datei in die .py Datei schreiben (Das ja sonst wenn TRE mit C angesprochen wird auch die .h Datei included wird und dort alle stehen, von der DLL bekommt man die glaubs nicht.

Gruss und viel Spass beim weiterprobieren
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Samstag 24. März 2007, 12:00

Hi

So habs nun geschafft mit Klammern, komischerweise muss ich diese Escapen für TRE (regex string ist r'a\([0-9]\)a')

Hier kannst du es nachschauen:
http://paste.pocoo.org/show/1258/

Gruss
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Samstag 24. März 2007, 15:36

Das liegt an den BREs (basic regexes). Um EREs zu verwenden, musst du das REG_EXTENDED flag für regcomp() verwenden.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten