odd.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2003 Zope Foundation and Contributors.
  4. # All Rights Reserved.
  5. #
  6. # This software is subject to the provisions of the Zope Public License,
  7. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  8. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  9. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  10. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  11. # FOR A PARTICULAR PURPOSE.
  12. #
  13. ##############################################################################
  14. """Odd meta class that doesn't subclass type.
  15. This is used for testing support for ExtensionClass in new interfaces.
  16. >>> class A(object):
  17. ... __metaclass__ = MetaClass
  18. ... a = 1
  19. ...
  20. >>> A.__name__
  21. 'A'
  22. >>> A.__bases__ == (object,)
  23. True
  24. >>> class B(object):
  25. ... __metaclass__ = MetaClass
  26. ... b = 1
  27. ...
  28. >>> class C(A, B): pass
  29. ...
  30. >>> C.__name__
  31. 'C'
  32. >>> int(C.__bases__ == (A, B))
  33. 1
  34. >>> a = A()
  35. >>> aa = A()
  36. >>> a.a
  37. 1
  38. >>> aa.a
  39. 1
  40. >>> aa.a = 2
  41. >>> a.a
  42. 1
  43. >>> aa.a
  44. 2
  45. >>> c = C()
  46. >>> c.a
  47. 1
  48. >>> c.b
  49. 1
  50. >>> c.b = 2
  51. >>> c.b
  52. 2
  53. >>> C.c = 1
  54. >>> c.c
  55. 1
  56. >>> import sys
  57. >>> if sys.version[0] == '2': # This test only makes sense under Python 2.x
  58. ... from types import ClassType
  59. ... assert not isinstance(C, (type, ClassType))
  60. >>> int(C.__class__.__class__ is C.__class__)
  61. 1
  62. """
  63. # class OddClass is an odd meta class
  64. class MetaMetaClass(type):
  65. def __getattribute__(cls, name):
  66. if name == '__class__':
  67. return cls
  68. # Under Python 3.6, __prepare__ gets requested
  69. return type.__getattribute__(cls, name)
  70. class MetaClass(object):
  71. """Odd classes
  72. """
  73. def __init__(self, name, bases, dict):
  74. self.__name__ = name
  75. self.__bases__ = bases
  76. self.__dict__.update(dict)
  77. def __call__(self):
  78. return OddInstance(self)
  79. def __getattr__(self, name):
  80. for b in self.__bases__:
  81. v = getattr(b, name, self)
  82. if v is not self:
  83. return v
  84. raise AttributeError(name)
  85. def __repr__(self): # pragma: no cover
  86. return "<odd class %s at %s>" % (self.__name__, hex(id(self)))
  87. MetaClass = MetaMetaClass('MetaClass',
  88. MetaClass.__bases__,
  89. {k: v for k, v in MetaClass.__dict__.items()
  90. if k not in ('__dict__',)})
  91. class OddInstance(object):
  92. def __init__(self, cls):
  93. self.__dict__['__class__'] = cls
  94. def __getattribute__(self, name):
  95. dict = object.__getattribute__(self, '__dict__')
  96. if name == '__dict__':
  97. return dict
  98. v = dict.get(name, self)
  99. if v is not self:
  100. return v
  101. return getattr(dict['__class__'], name)
  102. def __setattr__(self, name, v):
  103. self.__dict__[name] = v
  104. def __delattr__(self, name):
  105. raise NotImplementedError()
  106. def __repr__(self): # pragma: no cover
  107. return "<odd %s instance at %s>" % (
  108. self.__class__.__name__, hex(id(self)))