PYTHON 5
Attributeproxy.py Guest on 20th November 2020 06:05:57 PM
  1. #!/usr/bin/python3
  2. """
  3. =====================================================================================
  4. attributeproxy.py: provide defaults and optional warnings for missings attributes in
  5. a wrapped object; used by frigcal [1.2] for configs module settings; separate module,
  6. as it may be a useful elsewhere; see end of this file for expected usage patterns;
  7. =====================================================================================
  8. """
  9.  
  10. class AttributeProxy:
  11.     """
  12.    provide a default for any object's attribute that is missing;
  13.    catches and delegates all attribute fetches/sets to wrapped object;
  14.    """
  15.     __trace = False  # becomes _AttributeProxy__trace
  16.    
  17.     def __init__(self, wrappedobject, defaultvalue=None, warnof=False):
  18.         """
  19.        skip my own __setattr__ here
  20.        """
  21.         object.__setattr__(self, '_wrappedobject', wrappedobject)
  22.         object.__setattr__(self, '_defaultvalue',  defaultvalue)
  23.         object.__setattr__(self, '_warnof',        warnof)
  24.        
  25.     def __getattr__(self, name):
  26.         """
  27.        on self.name for undefined name
  28.        doesn't recur for self._X or __X: defined
  29.        """
  30.         if self.__trace: print('getattr', name)
  31.         if self._warnof and not hasattr(self._wrappedobject, name):
  32.             self.__warning(name)
  33.         return getattr(self._wrappedobject, name, self._defaultvalue)
  34.  
  35.     def __setattr__(self, name, value):
  36.         """
  37.        on self.name=value for all names
  38.        pass all other sets to wrapped object
  39.        """
  40.         if self.__trace: print('setattr', name, value)
  41.         setattr(self._wrappedobject, name, value)
  42.  
  43.     def __warning(self, name):
  44.         """
  45.        issue warning no missing attribute if enabled;
  46.        include type and object type names if present [1.2.3]
  47.        """
  48.         wrapped = self._wrappedobject
  49.         print('Warning: %s %s missing attribute "%s"' %
  50.                   (getattr(type(wrapped), '__name__', 'unknown'),
  51.                    getattr(wrapped, '__name__', 'object'),
  52.                    name), end='; ')
  53.         print('using default: %r' % self._defaultvalue)
  54.  
  55.  
  56. if __name__ == '__main__':
  57.     # self-test if run: no output before 'Finished' means tests passed
  58.     import sys, io
  59.     sys.stdout = io.StringIO()   # capture prints
  60.  
  61.     class C: a=1
  62.     i = C()
  63.     pC = AttributeProxy(C, warnof=True)    # wrap class
  64.     pi = AttributeProxy(i, 'dflt', True)   # wrap instance
  65.    
  66.     import attributeproxy as m             # import, not run
  67.     pm = AttributeProxy(m, warnof=True)    # wrap module
  68.  
  69.     assert pC.a == 1 and pC.x == None
  70.     assert pi.a == 1 and pi.x == 'dflt'
  71.     assert pm.x == None
  72.    
  73.     assert sys.stdout.getvalue() == (
  74.     "Warning: type C missing attribute \"x\"; using default: None\n"
  75.     "Warning: C object missing attribute \"x\"; using default: 'dflt'\n"
  76.     "Warning: module attributeproxy missing attribute \"x\"; using default: None\n")
  77.  
  78.     sys.stderr.write('Finished\n')
  79.     if sys.platform.startswith('win'):
  80.         sys.stderr.write('Press Enter\n'); input()  # keep open if clicked
  81.  
  82.  
  83. """
  84. =====================================================================================
  85. Usage patterns:
  86.  
  87. # module norm
  88. >>> from attributeproxy import AttributeProxy
  89. >>> import frigcal_configs as m
  90. >>> m.clickmode
  91. 'mouse'
  92. >>> m.x
  93. Traceback (most recent call last):
  94.  File "<stdin>", line 1, in <module>
  95. AttributeError: 'module' object has no attribute 'x'
  96.  
  97. # module wrapped
  98. >>> p = AttributeProxy(m)     # default None, no warning
  99. >>> p.clickmode
  100. 'mouse'
  101. >>> p.x
  102. >>> p = AttributeProxy(m, defaultvalue=True)
  103. >>> p.x
  104. True
  105. >>> p = AttributeProxy(m, defaultvalue='missing', warnof=True)
  106. >>> p.x
  107. Warning: module frigcal_configs missing attribute "x"; using default: 'missing'
  108. 'missing'
  109.  
  110. # built-ins
  111. >>> q = AttributeProxy([1], 99, True)
  112. >>> q.sort
  113. <built-in method sort of list object at 0x000000000289C448>
  114. >>> q.nonesuch
  115. Warning: list object missing attribute "nonesuch"; using default: 99
  116. 99
  117. >>> q = AttributeProxy(99, 1, True)
  118. >>> q.nonesuch
  119. Warning: int object missing attribute "nonesuch"; using default: 1
  120. 1
  121.  
  122. # class, instance
  123. >>> class C: a=1
  124. ...
  125. >>> q = AttributeProxy(C, 'absent', True)
  126. >>> q.a
  127. 1
  128. >>> q.x
  129. Warning: type C missing attribute "x"; using default: 'absent'
  130. 'absent'
  131. >>> q = AttributeProxy(C(), 'absent', True)
  132. >>> q.a
  133. 1
  134. >>> q.x
  135. Warning: C object missing attribute "x"; using default: 'absent'
  136. 'absent'
  137. =====================================================================================
  138. """

Paste is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.