Hallo,
ich würde gerne (bzw. muss) ein Modul für ein Netzwerkprotokoll welches für Python 2 geschrieben wurde, mit Python 3 verwenden.
Die einfachen Dinge erledigt das 2to3 Skript. Das Hauptproblem ist allerdings, dass an unendlich vielen Stellen das array modul mit "packet = array.array('c')" verwendet wird. Es werden viele Strings oder auch andere Daten in ein Array gewandelt, die dann letztenendes übers Netzwerk auf die Reise gehen. Aufgrund der tiefgreifenden Änderung bei der Ablage von Strings bei Python 3 ist das nicht mehr kompatibel.
Darum meine Frage, ob es irgendwo einen gleichwertigen Ersatz für das array Modul gibt, das die gleiche Funktionalität unter Python 3 wie unter Python 2 zur Verfügung stellt.
Ich habe testweise probiert die arrays durch ein bytearray() zu ersetzen, aber wenn ich dort Daten mit extend() anhängen will, muss ich den Typ des Parameters prüfen. Ist es ein String dann das encoding angeben, bei anderen Typen etwas anderes usw., es ist auf jeden Fall nicht ganz so einfach da ich jede Stelle einzeln anfassen müsste. Das Array Modul unter Python 2 scheint das alles automatisch gemacht zu haben.
Vielleicht hat ja einer einen heißen Tipp. Danke schonmal
Python 2 -> 3: Ersatz für array module bei Binärdaten
@Thomas_W123: dass Python2 nicht sauber zwischen Bytes und Strings unterscheidet, mußt Du jetzt bei Python3 eben ausbaden. Ein bytearray ist für Dein Netzwerkprotokoll wahrscheinlich schon der richtige Typ. Um ein händisches Umschreiben wirst Du aber nicht drumrum kommen. Blind aber irgendwelche encodings einzufügen ist aber der falsche Weg. Zum Schluß hast Du dann ein unwartbares Durcheinander von Strings und Bytes.
-
- User
- Beiträge: 8
- Registriert: Freitag 23. Juli 2010, 16:49
Das mit dem Durcheinander merke ich.
Das Problem ist aber, dass ein Parameter mal ein string ist, und mal z.B. auch wieder ein array objekt. Und das array-Modul in Python 2 hat wohl alles ohne Probleme "gefressen". Wahrscheinlich ist das der Grund warum Python 2 immer noch gerne für quick&dirty Hacks verwendet wird.
Zumindest ist das Modul das ich verwenden will nicht von mir entwickelt, darum kann ich gar nicht überblicken wo ich was anpassen muss damit es wieder funktioniert. Da ich aber sicher nicht der erste bin der sowas von 2 nach 3 konvertieren will, dachte ich mir evtl. gibt es irgendwo ein fertiges array Modul was eben unter 3 genauso funktioniert wie unter 2, eben mit fixem encoding wie z.B. ascii (hat sich bisher auch keiner drum gekümmert).
Das Problem ist aber, dass ein Parameter mal ein string ist, und mal z.B. auch wieder ein array objekt. Und das array-Modul in Python 2 hat wohl alles ohne Probleme "gefressen". Wahrscheinlich ist das der Grund warum Python 2 immer noch gerne für quick&dirty Hacks verwendet wird.
Zumindest ist das Modul das ich verwenden will nicht von mir entwickelt, darum kann ich gar nicht überblicken wo ich was anpassen muss damit es wieder funktioniert. Da ich aber sicher nicht der erste bin der sowas von 2 nach 3 konvertieren will, dachte ich mir evtl. gibt es irgendwo ein fertiges array Modul was eben unter 3 genauso funktioniert wie unter 2, eben mit fixem encoding wie z.B. ascii (hat sich bisher auch keiner drum gekümmert).
@Thomas_W123: Das ist etwas das geht schlicht nicht automatisch, da muss ein Mensch ran und entscheiden ob etwas Bytes oder eine echte Zeichenkette ist und entsprechend konvertieren falls nötig. Einfach ASCII annehmen geht ziemlich sicher nicht falls es sich tatsächlich um beliebige Binärdaten handelt, denn mit ASCII kann man ja so gar nicht den Wertebereich von Bytes abdecken.
-
- User
- Beiträge: 8
- Registriert: Freitag 23. Juli 2010, 16:49
Habs glaub ich soweit hinbekommen.
Ich habe die Vorkommen von "array.array('c')" durch "bytearray()" ersetzt.
Außerdem die Längenabfragen jedes Buffers von "buffer.buffer_info()[1]" durch "len(buffer)" ersetzt.
An der Stelle wo 'echte' Strings ins Spiel kommen, habe ich eine Typabfrage eingebaut. So in der Art:
In dem Netzwerkprotokoll ist kein Unicode zugelassen, darum sollte das mit dem einfachen encode passen denke ich mal. Wenn einer Umlaute reingibt, hat er eben Pech gehabt wenn es nicht funktioniert
Ich habe die Vorkommen von "array.array('c')" durch "bytearray()" ersetzt.
Außerdem die Längenabfragen jedes Buffers von "buffer.buffer_info()[1]" durch "len(buffer)" ersetzt.
An der Stelle wo 'echte' Strings ins Spiel kommen, habe ich eine Typabfrage eingebaut. So in der Art:
Code: Alles auswählen
if type(data) is str:
buf.extend(str.encode(data))
else:
buf.extend(data)
@Thomas_W123: Der Typtest ist unschön und das kodieren auf *diese* Weise ebenfalls. Besser wäre es mit `isinstance()` zu prüfen und die Methode auf dem Objekt aufzurufen statt ”statisch” den `str`-Typ zu verwenden.
-
- User
- Beiträge: 8
- Registriert: Freitag 23. Juli 2010, 16:49
Danke für den Hinweis. Musste mich erstmal einlesen wo da der Unterschied ist.
Habs jetzt so
Habs jetzt so
Code: Alles auswählen
if isinstance(data, str):
buf.extend(data.encode())
else:
buf.extend(data)
@Thomas_W123: wenn das schon nötig ist, wäre es besser, das in eine eigene Funktion auszulagern,
obwohl man solche Zweideutigkeiten vermeiden sollte. Um welches Netzwerkprotokoll handelt es sich denn? Dort muß doch geregelt sein, mit welchem Encoding Strings zu übertragen sind.
Code: Alles auswählen
def to_bytes(data):
return data.encode() if hasattr(data, "encode") else data
buf.extend(to_bytes(data))