0

Having some trouble translating these two methods from python2 to python3.

Python2:

def send(self, data):
    if self.debug:
        print 'Send:',
        print ':'.join('%02x' % ord(c) for c in data)
    l0 = len(data) & 0xFF
    l1 = (len(data) >> 8) & 0xFF
    d = chr(l0) + chr(l1) + data
    self.sock.send(d)

def recv(self):
    data = self.sock.recv(2)
    l0 = ord(data[0])
    l1 = ord(data[1])
    plen = l0 + (l1 << 8)
    data = self.sock.recv(plen)
    if self.debug:
        print 'Recv:',
        print ':'.join('%02x' % ord(c) for c in data)
    return data

Python 3 This what I got so far :

def send(self, data):
    if self.debug:
        print('Send:', end=' ')
        print(':'.join('%02x' % ord(c) for c in data))
    l0 = len(data.encode('utf-8')) & 0xFF
    l1 = (len(data.encode('utf-8')) >> 8) & 0xFF
    d = chr(l0) + chr(l1) + data
    self.sock.send(d)

def recv(self):
    data = self.sock.recv(2)
    l0 = ord(data[0])
    l1 = ord(data[1])
    plen = l0 + (l1 << 8)
    data = self.sock.recv(plen)
    if self.debug:
        print('Recv:', end=' ')
        print(':'.join('%02x' % ord(c) for c in data))
    return data

I keep getting this error:

TypeError: ord() expected string of length 1, but int found

Any help would be appreciated. Thank you

1
  • have you already consulted the 2to3 tool? The issue that is raising the error is that you have a bytes object instead of str which when iterated gives the ints directly so no need to call ord on it. Commented Mar 13, 2017 at 23:37

2 Answers 2

2

There are two main types of issues you need to address to make your code work in Python 3.

The biggest issue is that strings and bytes are no longer represented by the same types in Python 3. The str type is for Unicode strings, the bytes type is for binary data. Your data argument looks like it should probably be bytes (since you're sending it directly out on a socket). If you did want to support Unicode strings, you'd need to encode() them with some encoding (e.g. "UTF-8") before sending them over the socket.

Anyway, assuming data is a bytes instance, you'll need to make a few small changes to the code to address how a few APIs work different for str and bytes:

  1. Iterating on a bytes yields the individual byte values, but as integers, not as one-character bytestrings. This basically means you don't need the ord in the print calls, nor in the first parts of recv.

  2. The chr function creates a str, not a bytes instance, and you can't concatenate the different types together. Creating a bytes instance from an integer is a bit awkward (bytes(some_number) doesn't do what you want), but it is possible.

The other issue you have is much simpler to understand. In Python 3, print is a function rather than a statement, so you need parentheses around its arguments. It also uses different syntax to suppress line endings.

Here's a fully fixed version of your code:

def send(self, data):
    if self.debug:
        print('Send:', end='')                     # new way to suppress the newline
        print(':'.join('%02x' % c for c in data))  # add parentheses, no need for ord
    l0 = len(data) & 0xFF
    l1 = (len(data) >> 8) & 0xFF
    d = bytes([l0, l1]) + data                     # build prefix bytestring differently
    self.sock.send(d)

def recv(self):
    l0, l1 = self.sock.recv(2)              # no need for ord, unpack directly as ints
    plen = l0 + (l1 << 8)
    data = self.sock.recv(plen)
    if self.debug:
        print('Recv:', end='')
        print(':'.join('%02x' % c for c in data))
    return data

Note that the struct module may offer a more elegant way of encoding and decoding the length of your data to a bytestring. For instance, struct.pack("<H", len(data)) could replace several lines of the code in send (you wouldn't need l0 and l1).

Sign up to request clarification or add additional context in comments.

4 Comments

help(bytes) indicates "bytes(iterable_of_ints) -> bytes" and "bytes(int) -> bytes object of size given by the parameter initialized with null bytes" so to make a single character bytes object you just do bytes([num]) instead of bytes(num)
@TadhgMcDonald-Jensen: Yep, that's the awkwardness I was referring to. There's no need for bytes([l0]) + bytes([l1]). You can just build a single pre-concatentated bytestring from a list with both integers in it. The struct.pack function is even nicer (though it appears I got the sign for the required endianness wrong).
Yes but you never actually state why bytes(num) doesn't make a single byte, just that it doesn't do it. I figured I should mention what it actually does for the OP (Occurs to me I should have said that from the get go) Still this is a very well formed answer.
@Blckknght Thank you very much, this is very helpful !
0

insteed of print a use print (a) like: python 2.x:

def send(self, data):
    if self.debug:
        print 'Send:',
        print ':'.join('%02x' % ord(c) for c in data)
    l0 = len(data) & 0xFF
    l1 = (len(data) >> 8) & 0xFF
    d = chr(l0) + chr(l1) + data
    self.sock.send(d)

def recv(self):
    data = self.sock.recv(2)
    l0 = ord(data[0])
    l1 = ord(data[1])
    plen = l0 + (l1 << 8)
    data = self.sock.recv(plen)
    if self.debug:
        print 'Recv:',
        print ':'.join('%02x' % ord(c) for c in data)
    return data

python 3.x:

def send(self, data):
    if self.debug:
        print ('Send:'),
        print (':'.join('%02x' % ord(c) for c in data))
    l0 = len(data) & 0xFF
    l1 = (len(data) >> 8) & 0xFF
    d = chr(l0) + chr(l1) + data
    self.sock.send(d)

def recv(self):
    data = self.sock.recv(2)
    l0 = ord(data[0])
    l1 = ord(data[1])
    plen = l0 + (l1 << 8)
    data = self.sock.recv(plen)
    if self.debug:
        print ('Recv:'),
        print (':'.join('%02x' % ord(c) for c in data))
    return data

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.