From: YAMAMOTO Takashi <[email protected]>

From: YAMAMOTO Takashi <[email protected]>

Signed-off-by: YAMAMOTO Takashi <[email protected]>
Signed-off-by: Isaku Yamahata <[email protected]>
---
Changes:
- argument mangling to avoid clash with reserved keyword
- parameterize string codec
- pylint
---
 ryu/ofproto/ofproto_parser.py |   95 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 2 deletions(-)

diff --git a/ryu/ofproto/ofproto_parser.py b/ryu/ofproto/ofproto_parser.py
index 0db2fd7..395efec 100644
--- a/ryu/ofproto/ofproto_parser.py
+++ b/ryu/ofproto/ofproto_parser.py
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import collections
 import logging
 import struct
 import functools
@@ -61,7 +62,30 @@ def create_list_of_base_attributes(f):
     return wrapper
 
 
+_mapdict_key = lambda f, d, str_codec: dict([(k, f(v, str_codec))
+                                             for k, v in d.items()])
+
+
 class StringifyMixin(object):
+    # Some argument to __init__ is mungled in order to avlid name conflict
+    # with builtin name.
+    # The standard manguling is to append '_' in order to avoid name clash
+    # to reserved keyword.
+    #
+    # PEP8:
+    # Function and method arguments
+    #   If a function argument's name clashes with a reserved keyword,
+    #   it is generally better to append a single trailing underscore
+    #   rather than use an abbreviation or spelling corruption. Thus
+    #   class_ is better than clss. (Perhaps better is to avoid such
+    #   clashes by using a synonym.)
+    #
+    # grep __init__ *.py | grep '[^_]_\>' showed that
+    # 'len', 'property', 'set', 'type'
+    # A bit more generic way is adopted
+    import __builtin__
+    __RESERVED_KEYWORD = dir(__builtin__)
+
     def __str__(self):
         buf = ''
         sep = ''
@@ -72,6 +96,60 @@ class StringifyMixin(object):
         return self.__class__.__name__ + '(' + buf + ')'
     __repr__ = __str__  # note: str(list) uses __repr__ for elements
 
+    @staticmethod
+    def _encode_value(v, str_encoder):
+        if isinstance(v, (bytes, unicode)):
+            json_value = str_encoder(v)
+        elif isinstance(v, list):
+            json_value = map(StringifyMixin._encode_value, v, str_encoder)
+        elif isinstance(v, dict):
+            json_value = _mapdict_key(StringifyMixin._encode_value,
+                                      v, str_encoder)
+        else:
+            to_jsondict = getattr(v, 'to_jsondict', lambda v: v)
+            json_value = to_jsondict(v)
+        return json_value
+
+    def to_jsondict(self, str_encoder=None):
+        """returns an object to feed json.dumps()
+        """
+        str_encoder = str_encoder or (lambda v: v)
+        dict_ = {}
+        for k, v in ofp_attrs(self):
+            dict_[k] = self._encode_value(v, str_encoder)
+        return {self.__class__.__name__: dict_}
+
+    @staticmethod
+    def _decode_value(json_value, str_decoder):
+        if isinstance(json_value, (bytes, unicode)):
+            v = str_decoder(json_value)
+        elif isinstance(json_value, list):
+            v = map(StringifyMixin._decode_value, json_value, str_decoder)
+        elif isinstance(json_value, dict):
+            v = _mapdict_key(StringifyMixin._decode_value,
+                             json_value, str_decoder)
+        else:
+            v = json_value
+        return v
+
+    @classmethod
+    def from_jsondict(cls, dict_, str_decoder=None):
+        """create an instance from a result of json.loads()
+        """
+        str_decoder = str_decoder or (lambda v: v)
+        dict2 = {}
+        for k, v in dict_.iteritems():
+            if k in StringifyMixin.__RESERVED_KEYWORD:
+                k += '_'
+            dict2[k] = cls._decode_value(v, str_decoder)
+        return cls(**dict2)
+
+
+def ofp_from_jsondict(parser, jsondict, str_decoder=None):
+    assert len(jsondict) == 1
+    for k, v in jsondict.iteritems():
+        return getattr(parser, k).from_jsondict(v, str_decoder)
+
 
 class MsgBase(StringifyMixin):
     @create_list_of_base_attributes
@@ -162,8 +240,14 @@ def msg_pack_into(fmt, buf, offset, *args):
 
 
 def ofp_attrs(msg_):
-    base = getattr(msg, '_base_attributes', [])
-    for k, v in inspect.getmembers(msg):
+    # a special case for namedtuple which seems widely used in
+    # ofp parser implementations.
+    if hasattr(msg_, '_fields'):
+        for k in msg_._fields:
+            yield(k, getattr(msg_, k))
+        return
+    base = getattr(msg_, '_base_attributes', [])
+    for k, v in inspect.getmembers(msg_):
         if k.startswith('_'):
             continue
         if callable(v):
@@ -175,6 +259,13 @@ def ofp_attrs(msg_):
         yield (k, v)
 
 
+def namedtuple(typename, fields, **kwargs):
+    class _namedtuple(StringifyMixin,
+                      collections.namedtuple(typename, fields, **kwargs)):
+        pass
+    return _namedtuple
+
+
 def msg_str_attr(msg_, buf, attr_list=None):
     if attr_list is None:
         attr_list = ofp_attrs(msg_)
-- 
1.7.10.4


------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service 
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to