Skip to content

Commit 94d100e

Browse files
tarkatronicrobshakir
authored andcommitted
Improve the handling of strings and unicode (#188)
* Remove a couple of unicode references * Use six library for handling text Also cleaned up the import section to pass isort, and changed a few `type()` calls to use `isinstance`. * Improve the handling of unicode * Improve the handling of unicode * Improve a few of the tests and use unicode * Improve the unicode handling * Fix the string type checks * Fix up the unicode handling * Make the description unicode, just to complicate things. * Handle unicode for both python 2 and 3 * Fix slots * Make sure the uncaching of modules works in py3 * Make sure tox installs base requirements in the venv * Fix a couple more unicode pieces
1 parent 3ed7419 commit 94d100e

10 files changed

Lines changed: 105 additions & 110 deletions

File tree

pyangbind/lib/pybindJSON.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,13 @@
1919
"""
2020
from __future__ import unicode_literals
2121

22+
import copy
23+
import json
2224
from collections import OrderedDict
2325

24-
from pyangbind.lib.serialise import pybindJSONEncoder, pybindJSONDecoder, pybindJSONIOError
25-
from pyangbind.lib.serialise import pybindIETFJSONEncoder
26-
import json
27-
import copy
2826
import six
2927

30-
if six.PY3:
31-
unicode = str
28+
from pyangbind.lib.serialise import pybindIETFJSONEncoder, pybindJSONDecoder, pybindJSONEncoder, pybindJSONIOError
3229

3330

3431
def remove_path(tree, path):
@@ -55,7 +52,7 @@ def loads(d, parent_pymod, yang_base, path_helper=None, extmethods=None,
5552
# that this really expected a dict, so this check simply makes sure
5653
# that if the user really did give us a string, we're happy with that
5754
# without breaking other code.
58-
if isinstance(d, unicode) or isinstance(d, str):
55+
if isinstance(d, six.string_types + (six.text_type,)):
5956
d = json.loads(d, object_pairs_hook=OrderedDict)
6057
return pybindJSONDecoder.load_json(d, parent_pymod, yang_base,
6158
path_helper=path_helper, extmethods=extmethods, overwrite=overwrite)
@@ -64,7 +61,7 @@ def loads(d, parent_pymod, yang_base, path_helper=None, extmethods=None,
6461
def loads_ietf(d, parent_pymod, yang_base, path_helper=None,
6562
extmethods=None, overwrite=False):
6663
# Same as above, to allow for load_ietf to work the same way
67-
if isinstance(d, unicode) or isinstance(d, str):
64+
if isinstance(d, six.string_types + (six.text_type,)):
6865
d = json.loads(d, object_pairs_hook=OrderedDict)
6966
return pybindJSONDecoder.load_ietf_json(d, parent_pymod, yang_base,
7067
path_helper=path_helper, extmethods=extmethods, overwrite=overwrite)
@@ -141,14 +138,13 @@ def lookup_subdict(dictionary, key):
141138
for t in tree:
142139
keep = True
143140
for k, v in select.iteritems():
141+
v = six.text_type(v)
144142
if mode == 'default' or isinstance(tree, dict):
145-
if keep and not \
146-
unicode(lookup_subdict(tree[t], k.split("."))) == unicode(v):
143+
if (keep and not six.text_type(lookup_subdict(tree[t], k.split("."))) == v):
147144
keep = False
148145
else:
149146
# handle ietf case where we have a list and might have namespaces
150-
if keep and not \
151-
unicode(lookup_subdict(t, k.split("."))) == unicode(v):
147+
if (keep and not six.text_type(lookup_subdict(t, k.split("."))) == v):
152148
keep = False
153149
if not keep:
154150
key_del.append(t)

pyangbind/lib/serialise.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import json
2828
from collections import OrderedDict
2929
from decimal import Decimal
30+
31+
import six
3032
from enum import IntEnum
31-
from pyangbind.lib.yangtypes import safe_name, YANGBool
33+
34+
from pyangbind.lib.yangtypes import YANGBool, safe_name
3235

3336

3437
class WithDefaults(IntEnum):
@@ -96,10 +99,9 @@ def default(self, obj, mode='default'):
9699

97100
# Map based on YANG type
98101
if orig_yangt in ["leafref"]:
99-
return self.default(obj._get()) if hasattr(obj, "_get") \
100-
else unicode(obj)
102+
return self.default(obj._get()) if hasattr(obj, "_get") else six.text_type(obj)
101103
elif orig_yangt in ["int64", "uint64"]:
102-
return unicode(obj) if mode == "ietf" else int(obj)
104+
return six.text_type(obj) if mode == "ietf" else int(obj)
103105
elif orig_yangt in ["identityref"]:
104106
if mode == "ietf":
105107
try:
@@ -108,20 +110,20 @@ def default(self, obj, mode='default'):
108110
return "%s:%s" % (obj._enumeration_dict[obj]["@module"], obj)
109111
except KeyError:
110112
pass
111-
return unicode(obj)
113+
return six.text_type(obj)
112114
elif orig_yangt in ["int8", "int16", "int32", "uint8", "uint16", "uint32"]:
113115
return int(obj)
114116
elif orig_yangt in ["int64" "uint64"]:
115117
if mode == "ietf":
116-
return unicode(obj)
118+
return six.text_type(obj)
117119
else:
118120
return int(obj)
119121
elif orig_yangt in ["string", "enumeration"]:
120-
return unicode(obj)
122+
return six.text_type(obj)
121123
elif orig_yangt in ["binary"]:
122124
return obj.to01()
123125
elif orig_yangt in ["decimal64"]:
124-
return unicode(obj) if mode == "ietf" else float(obj)
126+
return six.text_type(obj) if mode == "ietf" else float(obj)
125127
elif orig_yangt in ["bool"]:
126128
return True if obj else False
127129
elif orig_yangt in ["empty"]:
@@ -149,14 +151,14 @@ def default(self, obj, mode='default'):
149151
for k, v in obj.iteritems():
150152
ndict[k] = self.default(v, mode=mode)
151153
return ndict
152-
elif type(obj) in [str, unicode]:
153-
return unicode(obj)
154-
elif type(obj) in [int, long]:
154+
elif isinstance(obj, six.string_types + (six.text_type,)):
155+
return six.text_type(obj)
156+
elif isinstance(obj, six.integer_types):
155157
return int(obj)
156-
elif type(obj) in [YANGBool, bool]:
158+
elif isinstance(obj, (YANGBool, bool)):
157159
return bool(obj)
158-
elif type(obj) in [Decimal]:
159-
return unicode(obj) if mode == "ietf" else float(obj)
160+
elif isinstance(obj, Decimal):
161+
return six.text_type(obj) if mode == "ietf" else float(obj)
160162

161163
raise AttributeError("Unmapped type: %s, %s, %s, %s, %s, %s" %
162164
(elem_name, orig_yangt, pybc, pyc,
@@ -171,12 +173,12 @@ def map_pyangbind_type(self, map_val, original_yang_type, obj, mode):
171173
return self.default(obj._get(), mode=mode)
172174
elif map_val in ["pyangbind.lib.yangtypes.RestrictedPrecisionDecimal", "RestrictedPrecisionDecimal"]:
173175
if mode == "ietf":
174-
return unicode(obj)
176+
return six.text_type(obj)
175177
return float(obj)
176178
elif map_val in ["bitarray.bitarray"]:
177179
return obj.to01()
178180
elif map_val in ["unicode"]:
179-
return unicode(obj)
181+
return six.text_type(obj)
180182
elif map_val in ["pyangbind.lib.yangtypes.YANGBool"]:
181183
if original_yang_type == "empty" and mode == "ietf":
182184
if obj:
@@ -193,12 +195,12 @@ def map_pyangbind_type(self, map_val, original_yang_type, obj, mode):
193195
elif map_val in ["long"]:
194196
int_size = getattr(obj, "_restricted_int_size", None)
195197
if mode == "ietf" and int_size == 64:
196-
return unicode(obj)
198+
return six.text_type(obj)
197199
return int(obj)
198200
elif map_val in ["container"]:
199201
return self._preprocess_element(obj.get(), mode=mode)
200202
elif map_val in ["decimal.Decimal"]:
201-
return unicode(obj) if mode == "ietf" else float(obj)
203+
return six.text_type(obj) if mode == "ietf" else float(obj)
202204

203205

204206
class pybindJSONDecoder(object):
@@ -333,7 +335,7 @@ def load_json(d, parent, yang_base, obj=None, path_helper=None,
333335

334336
@staticmethod
335337
def check_metadata_add(key, data, obj):
336-
keys = [unicode(k) for k in data]
338+
keys = [six.text_type(k) for k in data]
337339
if ("@" + key) in keys:
338340
for k, v in data["@" + key].iteritems():
339341
obj._add_metadata(k, v)

pyangbind/lib/xpathhelper.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@
2323
This module maintains an XML ElementTree for the registered Python
2424
classes, so that XPATH can be used to lookup particular items.
2525
"""
26+
from __future__ import unicode_literals
27+
28+
import uuid
2629
from collections import OrderedDict
2730

28-
from lxml import etree
2931
import regex
30-
import uuid
31-
from .yangtypes import safe_name
32+
import six
33+
from lxml import etree
34+
3235
from .base import PybindBase
36+
from .yangtypes import safe_name
3337

3438

3539
class YANGPathHelperException(Exception):
@@ -304,7 +308,7 @@ def _get_etree(self, object_path, caller=False):
304308
return retr_obj
305309

306310
def get(self, object_path, caller=False):
307-
if isinstance(object_path, str) or isinstance(object_path, unicode):
311+
if isinstance(object_path, six.string_types + (six.text_type,)):
308312
object_path = self._path_parts(object_path)
309313

310314
return [self._library[i.get("obj_ptr")]
@@ -323,7 +327,7 @@ def get_unique(self, object_path, caller=False,
323327

324328
def get_list(self, object_path, caller=False,
325329
exception_to_raise=YANGPathHelperException):
326-
if isinstance(object_path, str) or isinstance(object_path, unicode):
330+
if isinstance(object_path, six.string_types + (six.text_type,)):
327331
object_path = self._path_parts(object_path)
328332

329333
parent_obj = self.get_unique(object_path[:-1], caller=caller,

pyangbind/lib/yangtypes.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,15 @@
2121
"""
2222
from __future__ import unicode_literals
2323

24-
from decimal import Decimal
25-
from bitarray import bitarray
26-
import uuid
27-
import regex
2824
import collections
2925
import copy
26+
import uuid
27+
from decimal import Decimal
28+
29+
import regex
3030
import six
31+
from bitarray import bitarray
3132

32-
# For Python3
33-
if six.PY3:
34-
unicode = str
35-
basestring = str
3633
# Words that could turn up in YANG definition files that are actually
3734
# reserved names in Python, such as being builtin types. This list is
3835
# not complete, but will probably continue to grow.
@@ -130,7 +127,7 @@ def RestrictedClassType(*args, **kwargs):
130127
type of restriction placed on the class, and the restriction_arg gives
131128
any input data that this function needs.
132129
"""
133-
base_type = kwargs.pop("base_type", unicode)
130+
base_type = kwargs.pop("base_type", six.text_type)
134131
restriction_type = kwargs.pop("restriction_type", None)
135132
restriction_arg = kwargs.pop("restriction_arg", None)
136133
restriction_dict = kwargs.pop("restriction_dict", None)
@@ -140,7 +137,7 @@ def RestrictedClassType(*args, **kwargs):
140137
# it must be a list since a restricted class can encapsulate a restricted
141138
# class
142139
current_restricted_class_type = regex.sub("<(type|class) '(?P<class>.*)'>",
143-
"\g<class>", str(base_type))
140+
"\g<class>", six.text_type(base_type))
144141
if hasattr(base_type, "_restricted_class_base"):
145142
restricted_class_hint = getattr(base_type, "_restricted_class_base")
146143
restricted_class_hint.append(current_restricted_class_type)
@@ -252,15 +249,15 @@ def range_check(value):
252249

253250
def match_pattern_check(regexp):
254251
def mp_check(value):
255-
if not isinstance(value, basestring):
252+
if not isinstance(value, six.string_types + (six.text_type,)):
256253
return False
257254
if regex.match(convert_regexp(regexp), value):
258255
return True
259256
return False
260257
return mp_check
261258

262259
def in_dictionary_check(dictionary):
263-
return lambda i: unicode(i) in dictionary
260+
return lambda i: six.text_type(i) in dictionary
264261

265262
val = False
266263
try:
@@ -365,7 +362,7 @@ def TypedListType(*args, **kwargs):
365362
certain types (specified by allowed_type kwarg to the function)
366363
can be added to the list.
367364
"""
368-
allowed_type = kwargs.pop("allowed_type", unicode)
365+
allowed_type = kwargs.pop("allowed_type", six.text_type)
369366
if not isinstance(allowed_type, list):
370367
allowed_type = [allowed_type]
371368

@@ -409,11 +406,11 @@ def check(self, v):
409406
tmp = i(v)
410407
passed = True
411408
break
412-
elif i == unicode and isinstance(v, str):
413-
tmp = unicode(v)
409+
elif i == six.text_type and isinstance(v, six.string_types + (six.text_type,)):
410+
tmp = six.text_type(v)
414411
passed = True
415412
break
416-
elif i not in [unicode, str]:
413+
elif i not in six.string_types + (six.text_type,):
417414
# for anything other than string we try
418415
# and cast. Using things for string or
419416
# unicode gives us strange results because we get
@@ -501,7 +498,7 @@ def YANGListType(*args, **kwargs):
501498
extensions = kwargs.pop("extensions", None)
502499

503500
class YANGList(object):
504-
__slots__ = ('_pybind_generated_by', '_members', '_keyval',
501+
__slots__ = ('_members', '_keyval',
505502
'_contained_class', '_path_helper', '_yang_keys',
506503
'_ordered',)
507504
_pybind_generated_by = "YANGListType"
@@ -584,7 +581,7 @@ def __set(self, *args, **kwargs):
584581
# this is a list that does not have a key specified, and hence
585582
# we generate a uuid that is used as the key, the method then
586583
# returns the uuid for the upstream process to use
587-
k = str(uuid.uuid1())
584+
k = six.text_type(uuid.uuid1())
588585

589586
update = False
590587
if v is not None:
@@ -714,12 +711,12 @@ def _generate_key(self, *args, **kwargs):
714711
def _extract_key(self, obj):
715712
kp = self._keyval.split(" ")
716713
if len(kp) > 1:
717-
ks = unicode()
714+
ks = ''
718715
for k in kp:
719716
kv = getattr(obj, "_get_%s" % safe_name(k), None)
720717
if kv is None:
721718
raise KeyError("Invalid key attribute specified for object")
722-
ks += "%s " % unicode(kv())
719+
ks += "%s " % six.text_type(kv())
723720
return ks.rstrip(" ")
724721
else:
725722
kv = getattr(obj, "_get_%s" % safe_name(self._keyval), None)
@@ -918,7 +915,7 @@ def YANGDynClass(*args, **kwargs):
918915
clsslots = ['_default', '_mchanged', '_yang_name', '_choice', '_parent',
919916
'_supplied_register_path', '_path_helper', '_base_type',
920917
'_is_leaf', '_is_container', '_extensionsd',
921-
'_pybind_base_class', '_extmethods', '_is_keyval',
918+
'_extmethods', '_is_keyval',
922919
'_register_paths', '_namespace', '_yang_type',
923920
'_defining_module', '_metadata', '_is_config', '_cpresent',
924921
'_presence']
@@ -1176,7 +1173,7 @@ def __init__(self, *args, **kwargs):
11761173
self._ptr = False
11771174
self._require_instance = require_instance
11781175
self._type = "unicode"
1179-
self._utype = unicode
1176+
self._utype = six.text_type
11801177

11811178
if len(args):
11821179
value = args[0]
@@ -1228,15 +1225,15 @@ def __init__(self, *args, **kwargs):
12281225
if len(path_chk) == 1 and is_yang_leaflist(path_chk[0]):
12291226
index = 0
12301227
for i in path_chk[0]:
1231-
if unicode(i) == unicode(value):
1228+
if six.text_type(i) == six.text_type(value):
12321229
found = True
12331230
self._referenced_object = path_chk[0][index]
12341231
break
12351232
index += 1
12361233
else:
12371234
found = False
12381235
for i in path_chk:
1239-
if unicode(i) == unicode(value):
1236+
if six.text_type(i) == six.text_type(value):
12401237
found = True
12411238
self._referenced_object = i
12421239

0 commit comments

Comments
 (0)