You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by fo...@apache.org on 2018/11/07 15:10:07 UTC

[avro] branch master updated: AVRO-2234 Use MappingProxyType, not ImmutableDict (#337)

This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new 9e60e59  AVRO-2234 Use MappingProxyType, not ImmutableDict (#337)
9e60e59 is described below

commit 9e60e59c53e006629a341822a39a22fa35f8270c
Author: Michael A. Smith <mi...@smith-li.com>
AuthorDate: Wed Nov 7 10:10:01 2018 -0500

    AVRO-2234 Use MappingProxyType, not ImmutableDict (#337)
    
    Per the Rejection Notice of PEP-416, use MappingProxyType instead of
    creating our own implementation of ImmutableDict.
---
 lang/py3/avro/protocol.py | 14 ++++-------
 lang/py3/avro/schema.py   | 59 ++++++++++-------------------------------------
 2 files changed, 17 insertions(+), 56 deletions(-)

diff --git a/lang/py3/avro/protocol.py b/lang/py3/avro/protocol.py
index 629d2fd..2568fb4 100644
--- a/lang/py3/avro/protocol.py
+++ b/lang/py3/avro/protocol.py
@@ -21,6 +21,7 @@
 Protocol implementation.
 """
 
+from types import MappingProxyType
 
 import hashlib
 import json
@@ -28,8 +29,6 @@ import logging
 
 from avro import schema
 
-ImmutableDict = schema.ImmutableDict
-
 # ------------------------------------------------------------------------------
 # Constants
 
@@ -146,8 +145,7 @@ class Protocol(object):
 
     self._types = tuple(types)
     # Map: type full name -> type schema
-    self._type_map = (
-        ImmutableDict((type.fullname, type) for type in self._types))
+    self._type_map = MappingProxyType({type.fullname: type for type in self._types})
     # This assertion cannot fail unless we don't track named schemas properly:
     assert (len(self._types) == len(self._type_map)), (
         'Type list %r does not match type map: %r'
@@ -158,8 +156,7 @@ class Protocol(object):
 
     # Map: message name -> Message
     # Note that message names are simple names unique within the protocol.
-    self._message_map = ImmutableDict(
-        items=((message.name, message) for message in self._messages))
+    self._message_map = MappingProxyType({message.name: message for message in self._messages})
     if len(self._messages) != len(self._message_map):
       raise ProtocolParseException(
           'Invalid protocol %s with duplicate message name: %r'
@@ -227,7 +224,7 @@ class Protocol(object):
     return to_dump
 
   def __str__(self):
-    return json.dumps(self.to_json())
+    return json.dumps(self.to_json(), cls=schema.MappingProxyEncoder)
 
   def __eq__(self, that):
     to_cmp = json.loads(str(self))
@@ -319,7 +316,7 @@ class Message(object):
     return self._props
 
   def __str__(self):
-    return json.dumps(self.to_json())
+    return json.dumps(self.to_json(), cls=schema.MappingProxyEncoder)
 
   def to_json(self, names=None):
     if names is None:
@@ -399,4 +396,3 @@ def Parse(json_string):
         % (json_string, exn))
 
   return ProtocolFromJSONData(json_data)
-
diff --git a/lang/py3/avro/schema.py b/lang/py3/avro/schema.py
index 7ed3b54..0ebd41f 100644
--- a/lang/py3/avro/schema.py
+++ b/lang/py3/avro/schema.py
@@ -38,6 +38,7 @@ A schema may be one of:
  - Null.
 """
 
+from types import MappingProxyType
 
 import abc
 import collections
@@ -45,7 +46,7 @@ import json
 import logging
 import re
 
-logger = logging.getLogger(__name__) 
+logger = logging.getLogger(__name__)
 
 # ------------------------------------------------------------------------------
 # Constants
@@ -149,49 +150,13 @@ class SchemaParseException(AvroException):
   """Error while parsing a JSON schema descriptor."""
   pass
 
-
 # ------------------------------------------------------------------------------
-
-
-class ImmutableDict(dict):
-  """Dictionary guaranteed immutable.
-
-  All mutations raise an exception.
-  Behaves exactly as a dict otherwise.
-  """
-
-  def __init__(self, items=None, **kwargs):
-    if items is not None:
-      super(ImmutableDict, self).__init__(items)
-      assert (len(kwargs) == 0)
-    else:
-      super(ImmutableDict, self).__init__(**kwargs)
-
-  def __setitem__(self, key, value):
-    raise Exception(
-        'Attempting to map key %r to value %r in ImmutableDict %r'
-        % (key, value, self))
-
-  def __delitem__(self, key):
-    raise Exception(
-        'Attempting to remove mapping for key %r in ImmutableDict %r'
-        % (key, self))
-
-  def clear(self):
-    raise Exception('Attempting to clear ImmutableDict %r' % self)
-
-  def update(self, items=None, **kwargs):
-    raise Exception(
-        'Attempting to update ImmutableDict %r with items=%r, kwargs=%r'
-        % (self, args, kwargs))
-
-  def pop(self, key, default=None):
-    raise Exception(
-        'Attempting to pop key %r from ImmutableDict %r' % (key, self))
-
-  def popitem(self):
-    raise Exception('Attempting to pop item from ImmutableDict %r' % self)
-
+# Utilities
+class MappingProxyEncoder(json.JSONEncoder):
+  def default(self, obj):
+    if isinstance(obj, MappingProxyType):
+      return obj.copy()
+    return json.JSONEncoder.default(self, obj)
 
 # ------------------------------------------------------------------------------
 
@@ -255,7 +220,7 @@ class Schema(object, metaclass=abc.ABCMeta):
     Returns:
       A read-only dictionary of properties associated to this schema.
     """
-    return ImmutableDict(self._props)
+    return MappingProxyType(self._props)
 
   @property
   def other_props(self):
@@ -264,7 +229,7 @@ class Schema(object, metaclass=abc.ABCMeta):
 
   def __str__(self):
     """Returns: the JSON representation of this schema."""
-    return json.dumps(self.to_json())
+    return json.dumps(self.to_json(), cls=MappingProxyEncoder)
 
   @abc.abstractmethod
   def to_json(self, names):
@@ -620,7 +585,7 @@ class Field(object):
     return FilterKeysOut(items=self._props, keys=FIELD_RESERVED_PROPS)
 
   def __str__(self):
-    return json.dumps(self.to_json())
+    return json.dumps(self.to_json(), cls=MappingProxyEncoder)
 
   def to_json(self, names=None):
     if names is None:
@@ -1003,7 +968,7 @@ class RecordSchema(NamedSchema):
         raise SchemaParseException(
             'Duplicate field name %r in list %r.' % (field.name, field_desc_list))
       field_map[field.name] = field
-    return ImmutableDict(field_map)
+    return MappingProxyType(field_map)
 
   def __init__(
       self,