22
33from types import ModuleType
44
5+ try :
6+ from collections .abc import Mapping
7+ except ImportError :
8+ from collections import Mapping
9+
510from six import text_type
611
712try :
@@ -47,9 +52,6 @@ class MethodDispatcher(dict):
4752 """
4853
4954def __init__ (self ,items = ()):
50- # Using _dictEntries instead of directly assigning to self is about
51- # twice as fast. Please do careful performance testing before changing
52- # anything here.
5355_dictEntries = []
5456for name ,value in items :
5557if isinstance (name , (list ,tuple ,frozenset ,set )):
@@ -64,6 +66,36 @@ def __init__(self, items=()):
6466def __getitem__ (self ,key ):
6567return dict .get (self ,key ,self .default )
6668
69+ def __get__ (self ,instance ,owner = None ):
70+ return BoundMethodDispatcher (instance ,self )
71+
72+
73+ class BoundMethodDispatcher (Mapping ):
74+ """Wraps a MethodDispatcher, binding its return values to `instance`"""
75+ def __init__ (self ,instance ,dispatcher ):
76+ self .instance = instance
77+ self .dispatcher = dispatcher
78+
79+ def __getitem__ (self ,key ):
80+ # see https://docs.python.org/3/reference/datamodel.html#object.__get__
81+ # on a function, __get__ is used to bind a function to an instance as a bound method
82+ return self .dispatcher [key ].__get__ (self .instance )
83+
84+ def get (self ,key ,default ):
85+ if key in self .dispatcher :
86+ return self [key ]
87+ else :
88+ return default
89+
90+ def __iter__ (self ):
91+ return iter (self .dispatcher )
92+
93+ def __len__ (self ):
94+ return len (self .dispatcher )
95+
96+ def __contains__ (self ,key ):
97+ return key in self .dispatcher
98+
6799
68100# Some utility functions to deal with weirdness around UCS2 vs UCS4
69101# python builds