From 866c8dda5ce2373c134499d23ec761fef27d726c Mon Sep 17 00:00:00 2001 From: lily Date: Fri, 25 May 2018 17:30:45 -0700 Subject: [PATCH] #733 derrive python native types on read operation --- sdk/cpp/core/src/types.hpp | 7 +- sdk/cpp/core/src/value.cpp | 11 + sdk/cpp/core/src/value_list.cpp | 6 + sdk/python/core/python.cpp | 7 +- sdk/python/core/tests/test_sanity_types.py | 342 ++++++++++++------ sdk/python/core/ydk/types/py_types.py | 104 +++++- ydkgen/common.py | 38 ++ .../python/class_get_entity_path_printer.py | 51 +-- ydkgen/printer/python/class_inits_printer.py | 36 +- ydkgen/printer/python/enum_printer.py | 15 +- ydkgen/printer/python/namespace_printer.py | 65 +++- 11 files changed, 510 insertions(+), 172 deletions(-) diff --git a/sdk/cpp/core/src/types.hpp b/sdk/cpp/core/src/types.hpp index 59e35fa3b..e5630dd5f 100644 --- a/sdk/cpp/core/src/types.hpp +++ b/sdk/cpp/core/src/types.hpp @@ -236,7 +236,8 @@ enum class YType { boolean, enumeration, bits, - decimal64 + decimal64, + younion }; class YLeaf @@ -245,6 +246,7 @@ class YLeaf YLeaf(YType type, std::string name); ~YLeaf(); + YLeaf(YType type, std::string name, std::vector younions); YLeaf(const YLeaf& val); YLeaf(YLeaf&& val); @@ -303,6 +305,7 @@ class YLeaf std::string name; std::string value; YType type; + std::vector younions; Bits bits_value; }; @@ -311,6 +314,7 @@ class YLeafList { YLeafList(YType type, const std::string & name); virtual ~YLeafList(); + YLeafList(YType type, const std::string & name, std::vector younions); YLeafList(const YLeafList& val); YLeafList(YLeafList&& val); @@ -349,6 +353,7 @@ class YLeafList { std::vector values; YType type; std::string name; + std::vector younions; }; class YList diff --git a/sdk/cpp/core/src/value.cpp b/sdk/cpp/core/src/value.cpp index 2f2c5f689..70591b982 100644 --- a/sdk/cpp/core/src/value.cpp +++ b/sdk/cpp/core/src/value.cpp @@ -56,6 +56,7 @@ std::string to_str(YType t) TOSTRING(enumeration); TOSTRING(bits); TOSTRING(decimal64); + TOSTRING(younion); } return ""; #undef TOSTRING @@ -70,6 +71,16 @@ YLeaf::YLeaf(YType type, std::string name): { } +YLeaf::YLeaf(YType type, std::string name, std::vector younions): + is_set(false), + yfilter(YFilter::not_set), + name(name), + value(""), + type(type), + younions(younions) +{ +} + YLeaf::YLeaf(const YLeaf& val): is_set{val.is_set}, yfilter(YFilter::not_set), diff --git a/sdk/cpp/core/src/value_list.cpp b/sdk/cpp/core/src/value_list.cpp index 34a3c444c..84f52c23b 100644 --- a/sdk/cpp/core/src/value_list.cpp +++ b/sdk/cpp/core/src/value_list.cpp @@ -56,6 +56,7 @@ string to_string(YType t) TOSTRING(enumeration); TOSTRING(bits); TOSTRING(decimal64); + TOSTRING(younion); } return ""; } @@ -65,6 +66,11 @@ YLeafList::YLeafList(YType type, const std::string & name) { } +YLeafList::YLeafList(YType type, const std::string & name, std::vector younions) + : yfilter(YFilter::not_set), type(type), name(name), younions(younions) +{ +} + YLeafList::YLeafList(const YLeafList& other) : yfilter(YFilter::not_set), values(other.getYLeafs()), type(other.type), name(other.name) { diff --git a/sdk/python/core/python.cpp b/sdk/python/core/python.cpp index 325afeda7..8fd1abbf6 100644 --- a/sdk/python/core/python.cpp +++ b/sdk/python/core/python.cpp @@ -573,7 +573,8 @@ PYBIND11_MODULE(ydk_, ydk) .value("boolean", ydk::YType::boolean) .value("enumeration", ydk::YType::enumeration) .value("bits", ydk::YType::bits) - .value("decimal64", ydk::YType::decimal64); + .value("decimal64", ydk::YType::decimal64) + .value("younion", ydk::YType::younion); enum_(types, "ModelCachingOption") .value("common", ydk::path::ModelCachingOption::COMMON) @@ -665,6 +666,7 @@ PYBIND11_MODULE(ydk_, ydk) class_(types, "YLeaf") .def(init(), arg("leaf_type"), arg("name")) + .def(init>(), arg("leaf_type"), arg("name"), arg("younions")) .def("get", &ydk::YLeaf::get, return_value_policy::reference) .def("get_name_leafdata", &ydk::YLeaf::get_name_leafdata, return_value_policy::reference) .def(self == self, return_value_policy::reference) @@ -694,12 +696,14 @@ PYBIND11_MODULE(ydk_, ydk) .def_readonly("is_set", &ydk::YLeaf::is_set, return_value_policy::reference) .def_readonly("name", &ydk::YLeaf::name, return_value_policy::reference) .def_readonly("type", &ydk::YLeaf::type, return_value_policy::reference) + .def_readonly("younions", &ydk::YLeaf::younions, return_value_policy::reference) .def_readwrite("yfilter", &ydk::YLeaf::yfilter) .def_readwrite("value_namespace", &ydk::YLeaf::value_namespace) .def_readwrite("value_namespace_prefix", &ydk::YLeaf::value_namespace_prefix); class_(types, "YLeafList") .def(init(), arg("leaflist_type"), arg("name")) + .def(init>(), arg("leaflist_type"), arg("name"), arg("younions")) .def("getYLeafs", &ydk::YLeafList::getYLeafs) .def("get_name_leafdata", &ydk::YLeafList::get_name_leafdata) .def(self == self) @@ -728,6 +732,7 @@ PYBIND11_MODULE(ydk_, ydk) }) .def_readonly("name", &ydk::YLeafList::name, return_value_policy::reference) .def_readonly("type", &ydk::YLeafList::type, return_value_policy::reference) + .def_readonly("younions", &ydk::YLeafList::younions, return_value_policy::reference) .def_readwrite("yfilter", &ydk::YLeafList::yfilter); class_(providers, "NetconfServiceProvider") diff --git a/sdk/python/core/tests/test_sanity_types.py b/sdk/python/core/tests/test_sanity_types.py index 51bf47b1b..04f8cc117 100644 --- a/sdk/python/core/tests/test_sanity_types.py +++ b/sdk/python/core/tests/test_sanity_types.py @@ -87,11 +87,14 @@ def test_int8(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.number8), type(runner_read.ytypes.built_in_t.number8)) def test_int16(self): runner = Runner() @@ -99,11 +102,14 @@ def test_int16(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.number16), type(runner_read.ytypes.built_in_t.number16)) def test_int32(self): runner = Runner() @@ -111,23 +117,14 @@ def test_int32(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) - def test_bits(self): - runner = Runner() - runner.ytypes.built_in_t.bits_value['disable-nagle'] = True - self.crud.create(self.ncc, runner) - - # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) - - # Compare runners - self.assertEqual(runner, runner1) + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.number32), type(runner_read.ytypes.built_in_t.number32)) def test_int64(self): runner = Runner() @@ -135,11 +132,14 @@ def test_int64(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.number64), type(runner_read.ytypes.built_in_t.number64)) def test_uint8(self): runner = Runner() @@ -147,11 +147,14 @@ def test_uint8(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.u_number8), type(runner_read.ytypes.built_in_t.u_number8)) def test_uint16(self): runner = Runner() @@ -159,11 +162,14 @@ def test_uint16(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.u_number16), type(runner_read.ytypes.built_in_t.u_number16)) def test_uint32(self): runner = Runner() @@ -171,11 +177,14 @@ def test_uint32(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.u_number32), type(runner_read.ytypes.built_in_t.u_number32)) def test_uint64(self): runner = Runner() @@ -183,11 +192,31 @@ def test_uint64(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.u_number64), type(runner_read.ytypes.built_in_t.u_number64)) + + def test_bits(self): + runner = Runner() + runner.ytypes.built_in_t.bits_value['disable-nagle'] = True + self.crud.create(self.ncc, runner) + + # Read into Runner1 + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) + + # Compare runners + self.assertEqual(runner, runner_read) + + # Compare types + runner_type = type(runner.ytypes.built_in_t.bits_value['disable-nagle']) + read_type = type(runner_read.ytypes.built_in_t.bits_value['disable-nagle']) + self.assertEqual(runner_type, read_type) def test_decimal64(self): runner = Runner() @@ -195,11 +224,15 @@ def test_decimal64(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.deci64), type(runner_read.ytypes.built_in_t.deci64)) + self.assertEqual(type(runner.ytypes.built_in_t.deci64.value), type(runner_read.ytypes.built_in_t.deci64.value)) def test_string_1(self): runner = Runner() @@ -207,11 +240,14 @@ def test_string_1(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.name), type(runner_read.ytypes.built_in_t.name)) @unittest.skip("bytes currently not supported by pybind11, see #49") def test_string_2(self): @@ -233,11 +269,14 @@ def test_empty(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.emptee), type(runner_read.ytypes.built_in_t.emptee)) def test_boolean(self): runner = Runner() @@ -245,22 +284,28 @@ def test_boolean(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.bool_value), type(runner_read.ytypes.built_in_t.bool_value)) runner = Runner() runner.ytypes.built_in_t.bool_value = False self.crud.update(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.bool_value), type(runner_read.ytypes.built_in_t.bool_value)) def test_embedded_enum(self): runner = Runner() @@ -268,11 +313,14 @@ def test_embedded_enum(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.embeded_enum), type(runner_read.ytypes.built_in_t.embeded_enum)) def test_enum(self): runner = Runner() @@ -280,11 +328,14 @@ def test_enum(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.enum_value), type(runner_read.ytypes.built_in_t.enum_value)) def test_union(self): runner = Runner() @@ -292,11 +343,14 @@ def test_union(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.younion), type(runner_read.ytypes.built_in_t.younion)) def test_union_enum(self): runner = Runner() @@ -304,11 +358,14 @@ def test_union_enum(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.enum_int_value), type(runner_read.ytypes.built_in_t.enum_int_value)) def test_union_int(self): runner = Runner() @@ -316,23 +373,45 @@ def test_union_int(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.enum_int_value), type(runner_read.ytypes.built_in_t.enum_int_value)) def test_union_recursive(self): runner = Runner() - runner.ytypes.built_in_t.younion_recursive = 18 + runner.ytypes.built_in_t.younion_recursive = "123:45" self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.younion_recursive), type(runner_read.ytypes.built_in_t.younion_recursive)) + + @unittest.skip('Unable to handle this edge case.') + def test_union_recursive_tricky(self): + runner = Runner() + runner.ytypes.built_in_t.younion_recursive = "12345" + self.crud.create(self.ncc, runner) + + # Read into Runner1 + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) + + # Compare runners + self.assertEqual(runner, runner_read) + + # # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.younion_recursive), type(runner_read.ytypes.built_in_t.younion_recursive)) def test_union_list(self): runner = Runner() @@ -341,11 +420,14 @@ def test_union_list(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.llunion[0]), type(runner_read.ytypes.built_in_t.llunion[0])) @unittest.skip('ConfD internal error.') def test_bits_leaflist(self): @@ -365,6 +447,9 @@ def test_bits_leaflist(self): # Compare runners self.assertEqual(runner, runner1) + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.bits_llist[0]), type(runner_read.ytypes.built_in_t.bits_llist[0])) + def test_enum_leaflist(self): runner = Runner() runner.ytypes.built_in_t.enum_llist.append(YdkEnumTest.local) @@ -372,11 +457,14 @@ def test_enum_leaflist(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.enum_llist[0]), type(runner_read.ytypes.built_in_t.enum_llist[0])) def test_identity_leaflist(self): runner = Runner() @@ -385,11 +473,14 @@ def test_identity_leaflist(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.identity_llist[0]), type(runner_read.ytypes.built_in_t.identity_llist[0])) def test_union_complex_list(self): runner = Runner() @@ -397,24 +488,29 @@ def test_union_complex_list(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.younion_list[0]), type(runner_read.ytypes.built_in_t.younion_list[0])) def test_identityref(self): runner = Runner() - runner.ytypes.built_in_t.identity_ref_value = \ - ChildIdentity() + runner.ytypes.built_in_t.identity_ref_value = ChildIdentity() self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.identity_ref_value), type(runner_read.ytypes.built_in_t.identity_ref_value)) def test_status_enum(self): runner = Runner() @@ -422,11 +518,14 @@ def test_status_enum(self): self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.Status.not_connected), type(runner_read.ytypes.built_in_t.Status.not_connected)) @unittest.skip('No unique check') def test_leaflist_unique(self): @@ -454,50 +553,65 @@ def test_submodule(self): subtest.one_aug.number = 3 res = self.crud.create(self.ncc, subtest) - subtest1 = self.crud.read(self.ncc, SubTest()) + subtest_read = self.crud.read(self.ncc, SubTest()) # Compare runners - self.assertEqual(subtest, subtest1) + self.assertEqual(subtest, subtest_read) + + # Compare types + self.assertEqual(type(subtest.one_aug.name), type(subtest_read.one_aug.name)) + self.assertEqual(type(subtest.one_aug.number), type(subtest_read.one_aug.number)) def test_identity_from_other_module(self): runner = Runner() - runner.ytypes.built_in_t.identity_ref_value = \ - YdktestType() + runner.ytypes.built_in_t.identity_ref_value = YdktestType() self.crud.create(self.ncc, runner) # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.identity_ref_value), type(runner_read.ytypes.built_in_t.identity_ref_value)) def test_boolean_update_read(self): runner = Runner() runner.ytypes.built_in_t.bool_value = True self.crud.create(self.ncc, runner) - # Read into Runner1 - runner1 = Runner() - runner1 = self.crud.read(self.ncc, runner1) + # CRUD Read + runner_read = Runner() + runner_read = self.crud.read(self.ncc, runner_read) # Compare runners - self.assertEqual(runner, runner1) + self.assertEqual(runner, runner_read) + + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.bool_value), type(runner_read.ytypes.built_in_t.bool_value)) # Update the leaf and run update - runner1.ytypes.built_in_t.bool_value = True - self.crud.create(self.ncc, runner1) + runner = runner_read + runner_read = None + runner.ytypes.built_in_t.bool_value = True + self.crud.create(self.ncc, runner) + + # CRUD Read + runner_read = self.crud.read(self.ncc, Runner()) - # Read into Runner2 - runner2 = self.crud.read(self.ncc, Runner()) # Compare runners - self.assertEqual(runner2, runner1) + self.assertEqual(runner, runner_read) - # def test_binary(self): - # pass + # Compare types + self.assertEqual(type(runner.ytypes.built_in_t.bool_value), type(runner_read.ytypes.built_in_t.bool_value)) - # def test_binary_invalid(self): - # pass + def test_binary(self): + pass + + def test_binary_invalid(self): + pass def test_cascading_types(self): self._cascading_types_helper(CompInstType.unknown, CompInstType_.unknown) @@ -518,17 +632,27 @@ def _cascading_types_helper(self, enum1, enum2): # Compare runners self.assertEqual(ctypes, ctypesRead) + # Compare types + self.assertEqual(type(ctypes.comp_insttype), type(ctypesRead.comp_insttype)) + self.assertEqual(type(ctypes.comp_nicinsttype), type(ctypesRead.comp_nicinsttype)) + def test_capital_letters(self): + # Configure entity native = Native() gigabit_eth = Native.Interface.GigabitEthernet() gigabit_eth.name = "test" native.interface.gigabitethernet.append(gigabit_eth) + # Create and Read self.crud.create(self.ncc, native) read_entity = self.crud.read(self.ncc, Native()) + # Compare runners self.assertEqual(read_entity, native) + # Compare types + self.assertEqual(type(native.interface.gigabitethernet[0]), type(read_entity.interface.gigabitethernet[0])) + if __name__ == '__main__': device, non_demand, common_cache, timeout = get_device_info() diff --git a/sdk/python/core/ydk/types/py_types.py b/sdk/python/core/ydk/types/py_types.py index 3f109fb07..75f996902 100644 --- a/sdk/python/core/ydk/types/py_types.py +++ b/sdk/python/core/ydk/types/py_types.py @@ -22,12 +22,14 @@ - Entity """ from collections import OrderedDict -import logging +import logging, importlib from ydk_ import is_set from ydk.ext.types import Bits from ydk.ext.types import ChildrenMap +from ydk.ext.types import Decimal64 from ydk.ext.types import Enum as _Enum +from ydk.ext.types import Empty from ydk.ext.types import YLeaf as _YLeaf from ydk.ext.types import YLeafList as _YLeafList from ydk.ext.types import YType @@ -42,8 +44,11 @@ class YLeafList(_YLeafList): """ Wrapper class for YLeafList, add __repr__ and get list slice functionalities. """ - def __init__(self, ytype, leaf_name): - super(YLeafList, self).__init__(ytype, leaf_name) + def __init__(self, ytype, leaf_name, younions=None): + if younions is None: + super(YLeafList, self).__init__(ytype, leaf_name) + else: + super(YLeafList, self).__init__(ytype, leaf_name, younions) self.ytype = ytype self.leaf_name = leaf_name @@ -225,13 +230,71 @@ def has_operation(self): def set_value(self, path, value, name_space='', name_space_prefix=''): for name, leaf in self._leafs.items(): if leaf.name == path: + native_value = self._get_native_type(leaf, name, value,) if isinstance(leaf, _YLeaf): if isinstance(self.__dict__[name], Bits): self.__dict__[name][value] = True else: - self.__dict__[name] = value + self.__dict__[name] = native_value elif isinstance(leaf, _YLeafList): - self.__dict__[name].append(value) + self.__dict__[name].append(native_value) + + def _get_native_type(self, leaf, leaf_name, value): + result = None + if leaf.type != YType.younion: + result = self._get_native_type_helper(leaf.type, leaf_name, value) + else: + for valid_type in leaf.younions: + try: + result = self._get_native_type_helper(valid_type, leaf_name, value) + except: + pass + + if result is not None: + break + + if result is not None: + return result + else: + return value + + def _get_native_type_helper(self, leaf_type, leaf_name, value): + if leaf_type in (YType.uint8, YType.uint16, YType.uint32, YType.uint64, + YType.int8, YType.int16, YType.int32, YType.int64): + return int(value) + if leaf_type == YType.str: + return str(value) + if leaf_type == YType.boolean: + return value.lower() == 'true' + if leaf_type == YType.identityref: + path = self.__module__.split('.')[:-1] + path = '.'.join(path) + yang_ns = importlib.import_module('{}._yang_ns'.format(path)) + identityref_lookup = yang_ns.__dict__['IDENTITY_LOOKUP'] + module_name, class_name = identityref_lookup[value] + module = importlib.import_module(module_name) + identityref_type = getattr(module, class_name) + return identityref_type() + if leaf_type == YType.empty: + return Empty() + if leaf_type == YType.decimal64: + return Decimal64(value) + if leaf_type == YType.enumeration: + path = self.__module__.split('.')[:-1] + path = '.'.join(path) + yang_ns = importlib.import_module('{}._yang_ns'.format(path)) + enum_lookup = yang_ns.__dict__['ENUM_LOOKUP'] + + absolute_path = self.get_absolute_path() + if absolute_path == '': + absolute_path = self.get_segment_path() + lookup_key = '%s/%s' % (absolute_path, leaf_name) + module_name, enum_name = enum_lookup[lookup_key] + module = importlib.import_module(module_name) + enum_type = _get_enum_type(module, enum_name) + enumerator_name = enum_type._enumerator_name_lookup_table[value] + return enum_type.__dict__[enumerator_name] + return None def set_filter(self, path, yfilter): pass @@ -317,7 +380,8 @@ def _perform_setattr(self, clazz, leaf_names, name, value): "Please use list append or extend method." .format(value)) if isinstance(value, _Enum.YLeaf): - value = value.name + leaf = self._leafs[name] + leaf.set(value.name) if name in leaf_names and name in self.__dict__: # bits ..? prev_value = self.__dict__[name] @@ -351,10 +415,36 @@ def _perform_setattr(self, clazz, leaf_names, name, value): def __str__(self): return "{}.{}".format(self.__class__.__module__, self.__class__.__name__) - def _name_matches_yang_name(name, yang_name): return name == yang_name or yang_name.endswith(':'+name) +def _get_enum_type(module, enum_name): + # check if target enum isn't nested + if hasattr(module, enum_name): + return getattr(module, enum_name) + + # get the top level classes of the module + class_instances = [] + for attribute_name in dir(module): + attribute = getattr(module, attribute_name) + if isinstance(attribute, type) and attribute.__module__[:10] == 'ydk.models': + attribute_obj = attribute() + if isinstance(attribute_obj, Entity): + class_instances.append(attribute_obj) + + # breadth first search each class for the target enum type + i = 0 + while(i < len(class_instances)): + clazz = class_instances[i] + if hasattr(clazz, enum_name): + return getattr(clazz, enum_name) + + children = clazz.get_children() + for child_name in children: + child = children[child_name] + class_instances.append(child) + i += 1 + return None class EntityCollection(object): """ EntityCollection is a wrapper class around ordered dictionary collection of type OrderedDict. diff --git a/ydkgen/common.py b/ydkgen/common.py index 6da7c8377..92c8aecfb 100644 --- a/ydkgen/common.py +++ b/ydkgen/common.py @@ -378,6 +378,44 @@ def is_identityref_type_spec(type_spec): def is_match_all(pattern): return pattern in ('[^\*].*', '\*') +def get_absolute_path_prefix(clazz): + parents = [] + p = clazz + while p is not None and not isinstance(p, atypes.Package): + if p != clazz: + parents.append(p) + p = p.owner + + parents.reverse() + path = '' + for p in parents: + if len(path) == 0: + path += p.owner.stmt.arg + path += ':' + path += p.stmt.arg + else: + path += '/' + if p.stmt.i_module.arg != p.owner.stmt.i_module.arg: + path += p.stmt.i_module.arg + path += ':' + path += p.stmt.arg + slash = "" + if len(path) > 0: + slash = "/" + + path = "%s%s" % (path, slash) + return path + +def get_segment_path_prefix(clazz): + prefix = '' + if clazz.owner is not None: + if isinstance(clazz.owner, atypes.Package): + prefix += clazz.owner.stmt.arg + ':' + elif clazz.owner.stmt.i_module.arg != clazz.stmt.i_module.arg: + prefix += clazz.stmt.i_module.arg + ':' + prefix += clazz.stmt.arg + return prefix + def get_typedef_stmt(type_stmt): while all([hasattr(type_stmt, 'i_typedef') and type_stmt.i_typedef is not None]): diff --git a/ydkgen/printer/python/class_get_entity_path_printer.py b/ydkgen/printer/python/class_get_entity_path_printer.py index 88ec9baad..906c68f81 100644 --- a/ydkgen/printer/python/class_get_entity_path_printer.py +++ b/ydkgen/printer/python/class_get_entity_path_printer.py @@ -21,7 +21,7 @@ """ from ydkgen.api_model import Package -from ydkgen.common import has_list_ancestor, is_top_level_class +from ydkgen.common import get_absolute_path_prefix, get_segment_path_prefix, has_list_ancestor, is_top_level_class class GetSegmentPathPrinter(object): @@ -45,45 +45,27 @@ def print_output(self, clazz): self._print_get_ydk_segment_path_body(clazz) def _print_get_ydk_segment_path_body(self, clazz): - path='"' - if clazz.owner is not None: - if isinstance(clazz.owner, Package): - path+= clazz.owner.stmt.arg + ':' - elif clazz.owner.stmt.i_module.arg != clazz.stmt.i_module.arg: - path+=clazz.stmt.i_module.arg + ':' - - path+= clazz.stmt.arg - path+='"' predicates = '' insert_token = ' + ' key_props = clazz.get_key_props() for key_prop in key_props: predicates += insert_token - predicates += '"[' if key_prop.stmt.i_module.arg != clazz.stmt.i_module.arg: predicates += key_prop.stmt.i_module.arg predicates += ':' - predicates += key_prop.stmt.arg + '=' - predicates += "'" - predicates +='"' - predicates += insert_token - predicates += ('str(self.%s)') % key_prop.name + insert_token - predicates += '"' - predicates += "'" - predicates += ']"' - path = '%s%s' % (path, predicates) - + path = get_segment_path_prefix(clazz) + path = '"%s"%s' % (path, predicates) self.ctx.writeln("self._segment_path = lambda: %s" % path) @@ -105,36 +87,11 @@ def __init__(self, ctx): def print_output(self, clazz, leafs): """ - :param `api_model.Class` clazz The class object. - """ if not is_top_level_class(clazz) and not has_list_ancestor(clazz): self._print_absolute_path_body(clazz, leafs) def _print_absolute_path_body(self, clazz, leafs): - parents = [] - p = clazz - while p is not None and not isinstance(p, Package): - if p != clazz: - parents.append(p) - p = p.owner - - parents.reverse() - path = '' - for p in parents: - if len(path) == 0: - path += p.owner.stmt.arg - path += ':' - path += p.stmt.arg - else: - path += '/' - if p.stmt.i_module.arg != p.owner.stmt.i_module.arg: - path += p.stmt.i_module.arg - path += ':' - path += p.stmt.arg - slash = "" - if len(path) > 0: - slash = "/" - path = "%s%s" % (path, slash) + path = get_absolute_path_prefix(clazz) self.ctx.writeln('self._absolute_path = lambda: "%s%%s" %% self._segment_path()' % path) diff --git a/ydkgen/printer/python/class_inits_printer.py b/ydkgen/printer/python/class_inits_printer.py index 67a133416..29bc5620a 100644 --- a/ydkgen/printer/python/class_inits_printer.py +++ b/ydkgen/printer/python/class_inits_printer.py @@ -120,6 +120,14 @@ def _print_init_leafs_and_leaflists(self, clazz, leafs): for prop in leafs: leaf_name = prop.name ytype = self._get_type_name(prop.property_type) + valid_types = None + if ytype == 'enumeration': + pass + elif ytype == 'younion': + valid_types = _get_union_types(prop) + if valid_types is not None and len(valid_types) == 1: + ytype = valid_types[0] + valid_types = None leaf_type = 'YLeaf' declaration_stmt = 'self.%s = None' % leaf_name @@ -135,7 +143,10 @@ def _print_init_leafs_and_leaflists(self, clazz, leafs): clazz.stmt.top in prop.stmt.top.i_aug_targets)): yname = ':'.join([prop.stmt.top.arg, prop.stmt.arg]) - self.ctx.writeln("('%s', %s(YType.%s, '%s'))," % (leaf_name, leaf_type, ytype, yname)) + if valid_types is None: + self.ctx.writeln("('%s', %s(YType.%s, '%s'))," % (leaf_name, leaf_type, ytype, yname, )) + else: + self.ctx.writeln("('%s', %s(YType.%s, '%s', [%s]))," % (leaf_name, leaf_type, ytype, yname, ', '.join(valid_types))) declarations.append(declaration_stmt) self.ctx.lvl_dec() @@ -195,9 +206,9 @@ def _get_type_name(self, prop_type): elif prop_type.name == 'leafref': return 'str' elif prop_type.name == 'decimal64': - return 'str' + return 'decimal64' elif prop_type.name == 'union': - return 'str' + return 'younion' elif prop_type.name == 'binary': return 'str' elif prop_type.name == 'instance-identifier': @@ -212,6 +223,25 @@ def _get_type_name(self, prop_type): return 'str' return prop_type.name +def _get_union_types(prop): + restrictions = prop.property_type.types + i = 0 + valid_types = {} + while i < len(restrictions): + restriction = restrictions[i] + typ = restriction.i_type_spec.name + if typ == 'union': + restrictions.extend(restriction.i_type_spec.types) + else: + if typ == 'string': + typ = 'str' + typ = 'YType.%s' % typ + + if not valid_types.has_key(typ): + valid_types[typ] = True + i += 1 + return sorted(valid_types.keys()) + class ClassSetAttrPrinter(object): diff --git a/ydkgen/printer/python/enum_printer.py b/ydkgen/printer/python/enum_printer.py index 3de2c9304..ca4a0ae56 100644 --- a/ydkgen/printer/python/enum_printer.py +++ b/ydkgen/printer/python/enum_printer.py @@ -33,7 +33,7 @@ def print_enum(self, enum_class, no_meta_assign): assert isinstance(enum_class, Enum) self._print_enum_header(enum_class) self._print_enum_body(enum_class, no_meta_assign) - self._print_enum_trailer(enum_class) + self._print_enum_trailer() def _print_enum_header(self, enum_class): self.ctx.writeln('class %s(Enum):' % enum_class.name) @@ -41,6 +41,7 @@ def _print_enum_header(self, enum_class): def _print_enum_body(self, enum_class, no_meta_assign): self._print_enum_docstring(enum_class) + self._print_leaf_name_lookup_table(enum_class) self._print_enum_literals(enum_class) def _print_enum_docstring(self, enum_class): @@ -54,6 +55,16 @@ def _print_enum_docstring(self, enum_class): self.ctx.writeln('"""') self.ctx.bline() + def _print_leaf_name_lookup_table(self, enum_class): + line = '_enumerator_name_lookup_table = {' + for enum_literal in enum_class.literals: + key = enum_literal.stmt.arg + value = enum_literal.name + line = "%s'%s': '%s', " % (line, key, value) + line = '%s}' % line + self.ctx.writeln(line) + self.ctx.bline() + def _print_enum_literals(self, enum_class): for enum_literal in enum_class.literals: self._print_enum_literal(enum_literal) @@ -64,6 +75,6 @@ def _print_enum_literal(self, enum_literal): self.ctx.writeln('%s = Enum.YLeaf(%s, "%s")' % (name, value, enum_literal.stmt.arg)) self.ctx.bline() - def _print_enum_trailer(self, enum_class): + def _print_enum_trailer(self): self.ctx.lvl_dec() self.ctx.bline() diff --git a/ydkgen/printer/python/namespace_printer.py b/ydkgen/printer/python/namespace_printer.py index 5a12b94f5..dcd7e4565 100644 --- a/ydkgen/printer/python/namespace_printer.py +++ b/ydkgen/printer/python/namespace_printer.py @@ -19,8 +19,8 @@ Print capabilities for bundle package. """ from ydkgen.printer.file_printer import FilePrinter -from ydkgen.api_model import get_property_name - +from ydkgen.api_model import Class, Enum, Package, get_property_name +from ydkgen.common import get_absolute_path_prefix, get_module_name, get_segment_path_prefix class NamespacePrinter(FilePrinter): def __init__(self, ctx, one_class_per_module): @@ -35,6 +35,8 @@ def print_output(self, packages, bundle_name): self._print_capabilities(packages) self._print_entity_lookup(packages) self._print_namespace_lookup(packages) + self._print_identity_lookup(packages) + self._print_enum_lookup(packages) def _get_imports(self, packages): imports = set() @@ -98,3 +100,62 @@ def _print_namespace_lookup(self, packages): self.ctx.lvl_dec() self.ctx.writeln('}') self.ctx.bline() + + def _print_identity_lookup(self, packages): + packages = sorted(packages, key=lambda p:p.name) + + self.ctx.writeln('IDENTITY_LOOKUP = {') + self.ctx.lvl_inc() + for package in packages: + identities = [idx for idx in package.owned_elements if isinstance( + idx, Class) and idx.is_identity()] + identities = sorted(identities, key=lambda c: c.name) + for identity_clazz in identities: + self.ctx.writeln("'%s:%s':('%s', '%s')," % (get_module_name(identity_clazz.stmt), identity_clazz.stmt.arg, + identity_clazz.get_py_mod_name(), identity_clazz.qn())) + self.ctx.lvl_dec() + self.ctx.writeln('}') + self.ctx.bline() + + def _print_enum_lookup(self, packages): + packages = sorted(packages, key=lambda p:p.name) + + self.ctx.writeln('ENUM_LOOKUP = {') + self.ctx.lvl_inc() + + enum_leafs = [] + for package in packages: + class_index = 0 + classes = [elem for elem in package.owned_elements if isinstance(elem, Class) and not elem.is_identity()] + + while class_index < len(classes): + clazz = classes[class_index] + properties = sorted(clazz.properties(), key=lambda p:p.name) + for prop in properties: + if isinstance(prop.property_type, Enum): + data = (prop.owner, prop.name, prop.get_py_mod_name(), prop.property_type.name) + enum_leafs.append(data) + elif prop.property_type.name == 'union': + for typ in prop.property_type.types: + if typ.i_type_spec.name == 'enumeration': + if hasattr(typ, 'i_enum'): + enum = typ.i_enum + else: + enum = typ.i_typedef.i_enum + data = (prop.owner, prop.name, enum.get_py_mod_name(), enum.name) + enum_leafs.append(data) + classes.extend([nested_class for nested_class in clazz.owned_elements if isinstance(nested_class, Class)]) + class_index += 1 + + for clazz, leaf_name, module_name, enum_name in enum_leafs: + segpath_prefix = get_segment_path_prefix(clazz) + segment_path = '%s/%s' % (segpath_prefix, leaf_name) + abspath_prefix = get_absolute_path_prefix(clazz) + + key = '%s%s' % (abspath_prefix, segment_path) + value = "('%s', '%s')," % (module_name, enum_name) + self.ctx.writeln("'%s':%s" % (key, value)) + + self.ctx.lvl_dec() + self.ctx.writeln('}') + self.ctx.bline()