Skip to content

Commit

Permalink
Cut version 0.3.2 for release to PyPI.
Browse files Browse the repository at this point in the history
	* (M) pyangbind/lib/* - update files to fix PEP8 compliance issues.
	* (M) setup.py - update version.
	* (M) tests/* - update files for PEP8 compliance.
  • Loading branch information
robshakir committed Mar 16, 2016
1 parent 5c95949 commit f40d2d0
Show file tree
Hide file tree
Showing 20 changed files with 211 additions and 141 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -6,3 +6,4 @@ dist/*
tests/pyvirtualenv
dev/*
tmp/*
*.PEP8-ERRORS
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -40,3 +40,6 @@
WARNING).
* Adds support for carrying the namespace and defined module in a class.
* Adds a metadata element to carry JSON metadata that was received.

16-03-2016 - 0.3.2
* Fixes an issue relating to to identity value inheritance.
57 changes: 36 additions & 21 deletions pyangbind/lib/serialise.py
Expand Up @@ -32,13 +32,15 @@

import sys


class pybindJSONIOError(Exception):
pass


class pybindJSONUpdateError(Exception):
pass


class pybindJSONDecodeError(Exception):
pass

Expand Down Expand Up @@ -86,7 +88,7 @@ def default(self, obj, mode="default"):

if isinstance(obj, dict):
ndict = {}
for k,v in obj.iteritems():
for k, v in obj.iteritems():
ndict[k] = self.default(v, mode=mode)
return ndict

Expand Down Expand Up @@ -190,9 +192,9 @@ def default(self, obj, mode="default"):

return [self.default(i) for i in obj]


raise AttributeError("Unmapped type: %s" % original_yang_type)


class pybindJSONDecoder(object):
@staticmethod
def load_json(d, parent, yang_base, obj=None, path_helper=None,
Expand Down Expand Up @@ -231,21 +233,23 @@ def load_json(d, parent, yang_base, obj=None, path_helper=None,
for elem in chobj._pyangbind_elements:
unsetchildelem = getattr(chobj, "_unset_%s" % elem)
unsetchildelem()
pybindJSONDecoder.load_json(d[key], chobj, yang_base, obj=chobj, path_helper=path_helper)
pybindJSONDecoder.load_json(d[key], chobj, yang_base, obj=chobj,
path_helper=path_helper)
set_via_stdmethod = False
elif pybind_attr in ["YANGListType", "list"]:
# we need to add each key to the list and then skip a level in the
# JSON hierarchy
list_obj = getattr(obj, safe_name(key), None)
if list_obj is None:
raise pybindJSONDecodeError("Could not load list object with name %s" % key)
raise pybindJSONDecodeError("Could not load list object " +
"with name %s" % key)
ordered_list = getattr(list_obj, "_ordered", None)
if ordered_list:
# Put keys in order:
okeys = []
kdict = {}
for k,v in d[key].iteritems():
if not "__yang_order" in v:
for k, v in d[key].iteritems():
if "__yang_order" not in v:
# Element is not specified in terms of order, so
# push to a list that keeps this order
okeys.append(k)
Expand All @@ -264,7 +268,8 @@ def load_json(d, parent, yang_base, obj=None, path_helper=None,
if child_key not in chobj:
chobj.add(child_key)
parent = chobj[child_key]
pybindJSONDecoder.load_json(d[key][child_key], parent, yang_base, obj=parent, path_helper=path_helper)
pybindJSONDecoder.load_json(d[key][child_key], parent, yang_base,
obj=parent, path_helper=path_helper)
set_via_stdmethod = False
if overwrite:
for child_key in chobj:
Expand Down Expand Up @@ -305,8 +310,8 @@ def load_json(d, parent, yang_base, obj=None, path_helper=None,
def check_metadata_add(key, data, obj):
keys = [unicode(k) for k in data]
if ("@" + key) in keys:
for k,v in data["@" + key].iteritems():
obj._add_metadata(k,v)
for k, v in data["@" + key].iteritems():
obj._add_metadata(k, v)

@staticmethod
def load_ietf_json(d, parent, yang_base, obj=None, path_helper=None,
Expand Down Expand Up @@ -340,8 +345,8 @@ def load_ietf_json(d, parent, yang_base, obj=None, path_helper=None,

if key == "@":
# Handle whole container metadata object
for k,v in d[key].iteritems():
obj._add_metadata(k,v)
for k, v in d[key].iteritems():
obj._add_metadata(k, v)
continue
elif "@" in key:
# Don't handle metadata elements, each element
Expand All @@ -356,7 +361,9 @@ def load_ietf_json(d, parent, yang_base, obj=None, path_helper=None,
if attr_get is None:
raise AttributeError("Invalid attribute specified (%s)" % ykey)
pybindJSONDecoder.check_metadata_add(key, d, attr_get())
pybindJSONDecoder.load_ietf_json(d[key], None, None, obj=attr_get(), path_helper=path_helper, extmethods=extmethods, overwrite=overwrite)
pybindJSONDecoder.load_ietf_json(d[key], None, None, obj=attr_get(),
path_helper=path_helper, extmethods=extmethods,
overwrite=overwrite)
elif isinstance(d[key], list):
for elem in d[key]:
# if this is a list, then this is a YANG list
Expand All @@ -372,13 +379,15 @@ def load_ietf_json(d, parent, yang_base, obj=None, path_helper=None,
nobj = this_attr[k]
elif " " in this_attr._keyval:
kwargs = {}
for pkv,ykv in zip(this_attr._keyval.split(" "), this_attr._yang_keys.split(" ")):
for pkv, ykv in zip(this_attr._keyval.split(" "),
this_attr._yang_keys.split(" ")):
kwargs[pkv] = elem[ykv]
nobj = this_attr.add(**kwargs)
#pybindJSONDecoder.load_ietf_json(elem, None, None, obj=nobj, path_helper=path_helper, extmethods=extmethods, overwrite=overwrite)
else:
nobj = this_attr.add(elem[this_attr._yang_keys])
pybindJSONDecoder.load_ietf_json(elem, None, None, obj=nobj, path_helper=path_helper, extmethods=extmethods, overwrite=overwrite)
pybindJSONDecoder.load_ietf_json(elem, None, None, obj=nobj,
path_helper=path_helper, extmethods=extmethods,
overwrite=overwrite)
pybindJSONDecoder.check_metadata_add(key, d, nobj)
else:
std_method_set = True
Expand All @@ -396,11 +405,13 @@ def load_ietf_json(d, parent, yang_base, obj=None, path_helper=None,
else:
set_method = getattr(obj, "_set_%s" % safe_name(ykey), None)
if set_method is None:
raise AttributeError("Invalid attribute specified in JSON - %s" % (ykey))
raise AttributeError("Invalid attribute specified in JSON - %s"
% (ykey))
set_method(d[key])
pybindJSONDecoder.check_metadata_add(key, d, get_method())
return obj


class pybindIETFJSONEncoder(pybindJSONEncoder):
@staticmethod
def generate_element(obj, parent_namespace=None, flt=False):
Expand All @@ -415,18 +426,21 @@ def generate_element(obj, parent_namespace=None, flt=False):
for element_name in obj._pyangbind_elements:
element = getattr(obj, element_name, None)
yang_name = getattr(element, "yang_name", None)
yname = yang_name() if not yang_name is None else element_name
yname = yang_name() if yang_name is not None else element_name

if not element._namespace == parent_namespace:
# if the namespace is different, then precede with the module
# name as per spec.
yname = "%s:%s" % (element._defining_module, yname)

generated_by = getattr(element, "_pybind_generated_by", None)
if generated_by == "container":
d[yname] = pybindIETFJSONEncoder.generate_element(element, parent_namespace=element._namespace, flt=flt)
if generated_by == "container":
d[yname] = pybindIETFJSONEncoder.generate_element(element,
parent_namespace=element._namespace, flt=flt)
elif generated_by == "YANGListType":
d[yname] = [pybindIETFJSONEncoder.generate_element(i, parent_namespace=element._namespace, flt=flt) for i in element._members.itervalues()]
d[yname] = [pybindIETFJSONEncoder.generate_element(i,
parent_namespace=element._namespace, flt=flt)
for i in element._members.itervalues()]
else:
if flt and element._changed():
d[yname] = element
Expand All @@ -435,7 +449,8 @@ def generate_element(obj, parent_namespace=None, flt=False):
return d

def encode(self, obj):
return json.JSONEncoder.encode(self, self._preprocess_element(obj, mode="ietf"))
return json.JSONEncoder.encode(self,
self._preprocess_element(obj, mode="ietf"))

def default(self, obj, mode="ietf"):
return pybindJSONEncoder().default(obj, mode="ietf")
6 changes: 3 additions & 3 deletions pyangbind/lib/xpathhelper.py
Expand Up @@ -91,8 +91,8 @@ def get(self, path, caller=False):

class YANGPathHelper(PybindXpathHelper):
_attr_re = re.compile("^(?P<tagname>[^\[]+)(?P<args>(\[[^\]]+\])+)$")
_arg_re = re.compile("^((and|or) )?[@]?(?P<cmd>[a-zA-Z0-9\-\_:]+)([ ]+)?=([ ]+)?" +
"[\'\"]?(?P<arg>[^ ^\'^\"]+)([\'\"])?([ ]+)?" +
_arg_re = re.compile("^((and|or) )?[@]?(?P<cmd>[a-zA-Z0-9\-\_:]+)([ ]+)?" +
"=([ ]+)?[\'\"]?(?P<arg>[^ ^\'^\"]+)([\'\"])?([ ]+)?" +
"(?P<remainder>.*)")
_relative_path_re = re.compile("^(\.|\.\.)")

Expand Down Expand Up @@ -200,7 +200,7 @@ def _tagname_attributes(self, tag, normalise_namespace=True):
attributes[c] = a
tmp_arg = r
else:
raise XPathError("invalid attribute string specified" +
raise XPathError("invalid attribute string specified" +
"for %s" % tagname +
"(err part: %s (%s))" % (arg, tmp_arg))
return (tagname, attributes)
Expand Down
13 changes: 8 additions & 5 deletions pyangbind/lib/yangtypes.py
Expand Up @@ -82,6 +82,7 @@ def safe_name(arg):
# so that we can retrieve it when get() is called.
return arg


def RestrictedPrecisionDecimalType(*args, **kwargs):
"""
Function to return a new type that is based on decimal.Decimal with
Expand Down Expand Up @@ -854,7 +855,8 @@ def YANGDynClass(*args, **kwargs):
rpath = []
chk_path = "/" + "/".join(remove_path_attributes(rpath))
if chk_path in extmethods:
for method in [i for i in dir(extmethods[chk_path]) if not i.startswith("_")]:
for method in [i for i in dir(extmethods[chk_path])
if not i.startswith("_")]:
clsslots.append("_" + method)

class YANGBaseClass(base_type):
Expand Down Expand Up @@ -888,9 +890,11 @@ def __init__(self, *args, **kwargs):
self._metadata = {}

if self._extmethods:
chk_path = "/" + "/".join(remove_path_attributes(self._register_path()))
chk_path = \
"/" + "/".join(remove_path_attributes(self._register_path()))
if chk_path in self._extmethods:
for method in [i for i in dir(self._extmethods[chk_path]) if not i.startswith("_")]:
for method in [i for i in dir(self._extmethods[chk_path]) if
not i.startswith("_")]:
# Don't allow methods to be overwritten
if hasattr(self, "_" + method):
continue
Expand All @@ -902,7 +906,7 @@ def __init__(self, *args, **kwargs):
if default:
self._default = default
if len(args):
if not self._default is False:
if self._default is not False:
if not args[0] == self._default:
self._set()
else:
Expand Down Expand Up @@ -1099,7 +1103,6 @@ def __init__(self, *args, **kwargs):
self._type = re.sub("<(type|class) '(?P<class>.*)'>", "\g<class>",
str(get_method()._base_type))
self._ptr = True
#self._referenced_object = path_chk[0]
elif self._require_instance:
if not value:
self._referenced_object = None
Expand Down
19 changes: 12 additions & 7 deletions pyangbind/plugin/pybind.py
Expand Up @@ -262,7 +262,8 @@ def build_pybind(ctx, modules, fd):

ctx.pybind_common_hdr += "from operator import attrgetter\n"
if ctx.opts.use_xpathhelper:
ctx.pybind_common_hdr += "import pyangbind.lib.xpathhelper as xpathhelper\n"
ctx.pybind_common_hdr += "import pyangbind.lib.xpathhelper as " + \
"xpathhelper\n"
ctx.pybind_common_hdr += """from pyangbind.lib.yangtypes import """
ctx.pybind_common_hdr += """RestrictedPrecisionDecimalType, """
ctx.pybind_common_hdr += """RestrictedClassType, TypedListType\n"""
Expand Down Expand Up @@ -358,11 +359,14 @@ def build_pybind(ctx, modules, fd):
get_children(ctx, fd, rpcs, module, module, register_paths=False,
path="/%s_rpc" % (safe_name(module.arg)))


def build_identities(ctx, defnd):
def find_all_identity_values(item, definitions, values=list()):
new_values = [k for k in definitions[item] if not k in ["@module", "@namespace"] and not k in values]
new_values = [k for k in definitions[item] if k not
in ["@module", "@namespace"] and k not in values]
for v in new_values:
values.extend([i for i in find_all_identity_values(v, definitions, values=values) if not i in values])
values.extend([i for i in find_all_identity_values(v, definitions,
values=values) if i not in values])
values.extend(new_values)
return values

Expand Down Expand Up @@ -448,9 +452,10 @@ def find_all_identity_values(item, definitions, values=list()):
for identity in orig_identity_d:
vals = find_all_identity_values(identity, orig_identity_d, values=[])
for value in vals:
if not value in orig_identity_d[identity]:
identity_d[identity][value] = {k: v for k,v in
orig_identity_d[value].iteritems() if k in ["@module", "@namespace"]}
if value not in orig_identity_d[identity]:
identity_d[identity][value] = {k: v for k, v in
orig_identity_d[value].iteritems() if k in
["@module", "@namespace"]}

# Add entries to the class_map such that this identity can be referenced by
# elements that use this identity ref.
Expand Down Expand Up @@ -1280,7 +1285,7 @@ def get_element(ctx, fd, element, module, parent, path,

# Find element's namespace
namespace = element.i_orig_module.search_one("namespace").arg \
if hasattr(element, "i_orig_module") else None
if hasattr(element, "i_orig_module") else None
defining_module = element.i_orig_module.arg if \
hasattr(element, "i_orig_module") else None

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -12,7 +12,7 @@

# PyangBind uses the same versioning approach as OpenConfig - see
# http://www.openconfig.net/file-cabinet/Semantic_Versioning_for_OpenConfig.pdf?attredirects=0&d=1
version='0.3.1',
version='0.3.2',

description="PyangBind is a plugin for pyang which converts YANG data" + \
"models into a Python class hierarchy, such that Python " + \
Expand Down
16 changes: 11 additions & 5 deletions tests/extmethods/run.py
Expand Up @@ -6,6 +6,7 @@

TESTNAME = "extmethods"


class extmethodcls(object):
def commit(self, *args, **kwargs):
return "COMMIT_CALLED"
Expand Down Expand Up @@ -72,17 +73,22 @@ def main():

for chk in results:
method = getattr(x.item.one, "_" + chk[0], None)
assert (method is not None) == chk[1], "Method %s retrieved incorrectly, method was: %s" % method
assert (method is not None) == chk[1], \
"Method %s retrieved incorrectly, method was: %s" % method
if method is not None:
result = method()
assert result == chk[2], "Incorrect result returned from %s -> %s != %s" % (chk[0], result, chk[2])
assert result == chk[2], "Incorrect return from %s -> %s != %s" \
% (chk[0], result, chk[2])

expected_return = {'args': ('one',), 'kwargs': {'caller': ['item', 'one'], 'two': 2, 'path_helper': False}}
assert x.item.one._echo('one', two=2) == expected_return, "args+kwargs not echoed correctly"
expected_return = {'args': ('one',), 'kwargs': {'caller': ['item', 'one'],
'two': 2, 'path_helper': False}}
assert x.item.one._echo('one', two=2) == expected_return, \
"args+kwargs not echoed correctly"

try:
x.item.two = False
assert False, "incorrectly set an attribute that did not exist in extmethods"
assert False, \
"incorrectly set an attribute that did not exist in extmethods"
except AttributeError:
pass

Expand Down
5 changes: 2 additions & 3 deletions tests/identityref/run.py
Expand Up @@ -112,8 +112,8 @@ def main():
"id4 leaf was set incorrectly (%s: %s != %s)" % \
(k[0], k[1], passed)

for k in [("daughter", True), ("cousin", True), ("mother", True), ("aunt", True),
("greatgrandmother", False)]:
for k in [("daughter", True), ("cousin", True), ("mother", True),
("aunt", True), ("greatgrandmother", False)]:
passed = True
try:
i.test_container.id5 = k[0]
Expand All @@ -138,6 +138,5 @@ def main():
os.system("/bin/rm %s/bindings.pyc" % this_dir)



if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion tests/include-import/run.py
Expand Up @@ -31,7 +31,7 @@ def main():
assert pyangbindpath is not False, "could not resolve pyangbind directory"

this_dir = os.path.dirname(os.path.realpath(__file__))

cmd = "%s " % pythonpath
cmd += "%s --plugindir %s/pyangbind/plugin" % (pyangpath, pyangbindpath)
cmd += " -f pybind -o %s/bindings.py" % this_dir
Expand Down

0 comments on commit f40d2d0

Please sign in to comment.