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
