text: # test __delattr__ and __setattr__
  
  # feature test for __setattr__/__delattr__
  try:
      class Test():
          def __delattr__(self, attr): pass
      del Test().noexist
  except AttributeError:
      print('SKIP')
      raise SystemExit
  
  # this class just prints the calls to see if they were executed
  class A():
      def __getattr__(self, attr):
          print('get', attr)
          return 1
      def __setattr__(self, attr, val):
          print('set', attr, val)
      def __delattr__(self, attr):
          print('del', attr)
  a = A()
  
  # check basic behaviour
  print(getattr(a, 'foo'))
  setattr(a, 'bar', 2)
  delattr(a, 'baz')
  
  # check meta behaviour
  getattr(a, '__getattr__') # should not call A.__getattr__
  getattr(a, '__setattr__') # should not call A.__getattr__
  getattr(a, '__delattr__') # should not call A.__getattr__
  setattr(a, '__setattr__', 1) # should call A.__setattr__
  delattr(a, '__delattr__') # should call A.__delattr__
  
  # this class acts like a dictionary
  class B:
      def __init__(self, d):
          # store the dict in the class, not instance, so
          # we don't get infinite recursion in __getattr_
          B.d = d
  
      def __getattr__(self, attr):
          if attr in B.d:
              return B.d[attr]
          else:
              raise AttributeError(attr)
  
      def __setattr__(self, attr, value):
          B.d[attr] = value
  
      def __delattr__(self, attr):
          del B.d[attr]
  
  a = B({"a":1, "b":2})
  print(a.a, a.b)
  a.a = 3
  print(a.a, a.b)
  del a.a
  try:
      print(a.a)
  except AttributeError:
      print("AttributeError")
  
  # test object.__setattr__
  class C:
      def __init__(self):
          pass
  
      def __setattr__(self, attr, value):
          print(attr, "=", value)
  
      def __delattr__(self, attr):
          print("del", attr)
  
  c = C()
  c.a = 5
  try:
      print(c.a)
  except AttributeError:
      print("AttributeError")
  
  object.__setattr__(c, "a", 5)
  super(C, c).__setattr__("b", 6)
  print(c.a)
  print(c.b)
  
  try:
      # attribute name must be string
      object.__setattr__(c, 5, 5)
  except TypeError:
      print("TypeError")
  
  
  # test object.__delattr__
  del c.a
  print(c.a)
  
  object.__delattr__(c, "a")
  try:
      print(c.a)
  except AttributeError:
      print("AttributeError")
  
  super(C, c).__delattr__("b")
  try:
      print(c.b)
  except AttributeError:
      print("AttributeError")
  
  try:
      object.__delattr__(c, "c")
  except AttributeError:
      print("AttributeError")
  