3

I am creating a python wrapper around a dll and am trying to make it compatible with both Python 2 and 3. Some of the functions in the dll only take in bytes and return bytes. This is fine on Py2 as I can just deal with strings, but on Py3 I need to convert unicode to bytes for input then bytes to unicode for the output.

For example:

import ctypes
from ctypes import util

path = util.find_library(lib)
dll = ctypes.windll.LoadLibrary(path)

def some_function(str_input):
   #Will need to convert string to bytes in the case of Py3
   bytes_output = dll.some_function(str_input)
   return bytes_output # Want this to be str (bytes/unicode for py2/3)

What is the best way to ensure compatibility here? Would it be fine just to use sys.version_info and encode/decode appropriately or what is the most accepted way to ensure compatibility between versions in this case?

pbreach
  • 16,049
  • 27
  • 82
  • 120

1 Answers1

1

I'd generally avoid hard checking for Python interpreter versions.

You might find this document helpful: http://python-future.org/compatible_idioms.html#strings-and-bytes

Also, note that you can use this import for unicode literals:

from __future__ import unicode_literals

And for byte strings:

# Python 2 and 3
s = b'This must be a byte-string'

As for the best way to convert string to bytes: https://stackoverflow.com/a/7585619/295246

The recommended way of converting a String to Bytes in Python 3 (as extracted from the link above) is to do as follows:

>>> a = 'some words'
>>> b = a.encode('utf-8')
>>> print(b)
b'some words'
>>> c = b.decode('utf-8')
>>> print(c)
'some words'
>>> isinstance(b, bytes)
True
>>> isinstance(b, str)
False
>>> isinstance(c, str)
True
>>> isinstance(c, bytes)
False

You could also do bytes(a, 'utf-8'), but the aforementioned way is more Pythonic (because you can inversely decode the same way from bytes back to str).

Community
  • 1
  • 1
HEADLESS_0NE
  • 3,416
  • 4
  • 32
  • 51
  • Okay great! So then by first using `from builtins import bytes` (with a try-except for `ImportError` on Py2) one could just use `bytes(str_input)` to ensure bytes input to the dll, then use say `str(bytes_output)` to ensure the output is `str` for the given Python version? – pbreach Apr 19 '16 at 16:30
  • Above comment is based on the first link. In the case that I've shown there are no literals but I think there are some sections in the rest of my code where literal conversion will be useful. – pbreach Apr 19 '16 at 16:44
  • 1
    That should work, as long as you do put it in a try-except like you've said. You could also convert only when needed by first asserting that x is an instance of `str` or `bytes`. In Python 2, if you have `x=b'something'` and check `isinstance(x, str)` and `isinstance(x, bytes)`, both will return `True`. However, in Python 3, `isinstance(x, str)` wil return `False`. Does that help? – HEADLESS_0NE Apr 19 '16 at 17:24
  • I've edited my answer to give you more insight into what I was talking about and the best way to convert a bytes to string (and vice-versa) in Python 3. – HEADLESS_0NE Apr 19 '16 at 18:55
  • @pbreach I'm not sure if you're using an IDE, but you might want to look into the latest release of PyCharm Community Edition. It has Python 2 and Python 3 type hinting and compatibility inspection. – HEADLESS_0NE Apr 19 '16 at 19:24