Skip to content

Commit 653ad58

Browse files
committed
Use Unicode strings throughout library
Python 3 will require it, so also do it in Python 2 for consistency.
1 parent 0c1c073 commit 653ad58

File tree

2 files changed

+45
-19
lines changed

2 files changed

+45
-19
lines changed

openslide/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@
3737

3838
__library_version__ = lowlevel.get_version()
3939

40-
PROPERTY_NAME_COMMENT = 'openslide.comment'
41-
PROPERTY_NAME_VENDOR = 'openslide.vendor'
42-
PROPERTY_NAME_QUICKHASH1 = 'openslide.quickhash-1'
43-
PROPERTY_NAME_BACKGROUND_COLOR = 'openslide.background-color'
44-
PROPERTY_NAME_OBJECTIVE_POWER = 'openslide.objective-power'
45-
PROPERTY_NAME_MPP_X = 'openslide.mpp-x'
46-
PROPERTY_NAME_MPP_Y = 'openslide.mpp-y'
40+
PROPERTY_NAME_COMMENT = u'openslide.comment'
41+
PROPERTY_NAME_VENDOR = u'openslide.vendor'
42+
PROPERTY_NAME_QUICKHASH1 = u'openslide.quickhash-1'
43+
PROPERTY_NAME_BACKGROUND_COLOR = u'openslide.background-color'
44+
PROPERTY_NAME_OBJECTIVE_POWER = u'openslide.objective-power'
45+
PROPERTY_NAME_MPP_X = u'openslide.mpp-x'
46+
PROPERTY_NAME_MPP_Y = u'openslide.mpp-y'
4747

4848
class AbstractSlide(object):
4949
"""The base class of a slide object."""

openslide/lowlevel.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# openslide-python - Python bindings for the OpenSlide library
33
#
4-
# Copyright (c) 2010-2011 Carnegie Mellon University
4+
# Copyright (c) 2010-2013 Carnegie Mellon University
55
#
66
# This library is free software; you can redistribute it and/or modify it
77
# under the terms of version 2.1 of the GNU Lesser General Public License
@@ -91,6 +91,25 @@ def from_param(cls, obj):
9191
raise ValueError("Passing closed slide object")
9292
return obj
9393

94+
class _utf8_p(object):
95+
"""Wrapper class to convert string arguments to bytes."""
96+
97+
if sys.version[0] == '2':
98+
_bytes_type = str
99+
_str_type = unicode
100+
else:
101+
_bytes_type = bytes
102+
_str_type = str
103+
104+
@classmethod
105+
def from_param(cls, obj):
106+
if isinstance(obj, cls._bytes_type):
107+
return obj
108+
elif isinstance(obj, cls._str_type):
109+
return obj.encode()
110+
else:
111+
raise TypeError('Incorrect type')
112+
94113
# check for errors opening an image file and wrap the resulting handle
95114
def _check_open(result, _func, _args):
96115
if result is None:
@@ -106,22 +125,29 @@ def _check_open(result, _func, _args):
106125
def _check_close(_result, _func, args):
107126
args[0].invalidate()
108127

128+
# Convert returned byte array, if present, into a string
129+
def _check_string(result, func, _args):
130+
if func.restype is c_char_p and result is not None:
131+
return result.decode(errors='replace')
132+
else:
133+
return result
134+
109135
# check if the library got into an error state after each library call
110-
def _check_error(result, _func, args):
136+
def _check_error(result, func, args):
111137
err = get_error(args[0])
112138
if err is not None:
113139
raise OpenSlideError(err)
114-
return result
140+
return _check_string(result, func, args)
115141

116-
# Convert returned NULL-terminated string array into a list
142+
# Convert returned NULL-terminated char** into a list of strings
117143
def _check_name_list(result, func, args):
118144
_check_error(result, func, args)
119145
names = []
120146
for i in count():
121147
name = result[i]
122148
if not name:
123149
break
124-
names.append(name)
150+
names.append(name.decode(errors='replace'))
125151
return names
126152

127153
# resolve and return an OpenSlide function with the specified properties
@@ -145,13 +171,13 @@ def _load_image(buf, size):
145171
return PIL.Image.frombuffer('RGBA', size, buf, 'raw', 'RGBa', 0, 1)
146172

147173
try:
148-
get_version = _func('openslide_get_version', c_char_p, [], None)
174+
get_version = _func('openslide_get_version', c_char_p, [], _check_string)
149175
except AttributeError:
150176
raise OpenSlideError('OpenSlide >= 3.3.0 required')
151177

152-
can_open = _func('openslide_can_open', c_bool, [c_char_p], None)
178+
can_open = _func('openslide_can_open', c_bool, [_utf8_p], None)
153179

154-
open = _func('openslide_open', c_void_p, [c_char_p], _check_open)
180+
open = _func('openslide_open', c_void_p, [_utf8_p], _check_open)
155181

156182
close = _func('openslide_close', None, [_OpenSlide], _check_close)
157183

@@ -188,27 +214,27 @@ def read_region(slide, x, y, level, w, h):
188214
_read_region(slide, buf, x, y, level, w, h)
189215
return _load_image(buf, (w, h))
190216

191-
get_error = _func('openslide_get_error', c_char_p, [_OpenSlide], None)
217+
get_error = _func('openslide_get_error', c_char_p, [_OpenSlide], _check_string)
192218

193219
get_property_names = _func('openslide_get_property_names', POINTER(c_char_p),
194220
[_OpenSlide], _check_name_list)
195221

196222
get_property_value = _func('openslide_get_property_value', c_char_p,
197-
[_OpenSlide, c_char_p])
223+
[_OpenSlide, _utf8_p])
198224

199225
get_associated_image_names = _func('openslide_get_associated_image_names',
200226
POINTER(c_char_p), [_OpenSlide], _check_name_list)
201227

202228
_get_associated_image_dimensions = \
203229
_func('openslide_get_associated_image_dimensions', None,
204-
[_OpenSlide, c_char_p, POINTER(c_int64), POINTER(c_int64)])
230+
[_OpenSlide, _utf8_p, POINTER(c_int64), POINTER(c_int64)])
205231
def get_associated_image_dimensions(slide, name):
206232
w, h = c_int64(), c_int64()
207233
_get_associated_image_dimensions(slide, name, byref(w), byref(h))
208234
return w.value, h.value
209235

210236
_read_associated_image = _func('openslide_read_associated_image', None,
211-
[_OpenSlide, c_char_p, POINTER(c_uint32)])
237+
[_OpenSlide, _utf8_p, POINTER(c_uint32)])
212238
def read_associated_image(slide, name):
213239
w, h = get_associated_image_dimensions(slide, name)
214240
buf = (w * h * c_uint32)()

0 commit comments

Comments
 (0)