Lichen

tests/methods_unbound.py

588:316c1c90b643
2017-02-17 Paul Boddie Eliminated superfluous accessor instructions loading static invocation targets. Added a test of nested calls employing explicitly retained contexts. method-wrapper-for-context
     1 class C:     2      3     "Class providing class and instance attributes."     4      5     def __init__(self):     6         self.a = 1     7      8     def m(self, x):     9         return x    10     11 class D:    12     13     "An alternative class."    14     15     pass    16     17 def getc():    18     19     "Return an instance of C to test object suitability."    20     21     return C()    22     23 def getd():    24     25     "Return an instance of D to test object suitability."    26     27     return D()    28     29 def f(obj, i):    30     31     """    32     Obtain an attribute on 'obj', performing an operation depending on 'i'.    33     This tests attribute access and invocation.    34     """    35     36     if i:    37         return obj.m(i)         # should cause access to an unbound method    38     else:    39         return obj.m    40     41 def g(obj, i):    42     43     """    44     Obtain an attribute on 'obj', performing an operation depending on 'i'.    45     This tests attribute access and invocation, restricting 'obj' using a guard.    46     """    47     48     obj.a                       # only provided by instances of C    49     if i:    50         return obj.m(i)         # should use the method directly since obj is an instance    51     else:    52         return obj.m    53     54 def h(obj, fn):    55     56     """    57     Obtain an attribute on 'obj', performing an operation depending on 'fn'.    58     This tests attribute access and invocation, restricting 'obj' using a guard    59     on a re-assignment of the name.    60     """    61     62     if fn:    63         obj = fn()    64         obj.a                   # only provided by instances of C    65         return obj.m(1)    66     else:    67         return obj.m    68     69 # Main program.    70     71 c = C()    72 d = D()    73     74 try:    75     print f(C, 1)               # fails    76 except UnboundMethodInvocation:    77     print "f(C, 1): Unbound method is not callable."    78     79 print f(c, 1)                   # 1    80     81 try:    82     print f(d, 1)               # should fail with an error caused by a guard    83 except TypeError:    84     print "f(d, 1): d is not a suitable argument."    85     86 # Get an unbound method, C.m.    87     88 fn = f(C, 0)    89     90 try:    91     print fn(2)                 # fails    92 except UnboundMethodInvocation:    93     print "fn(2): Unbound method is not callable."    94     95 print get_using(fn, c)(2)       # 2    96     97 # Repeat with fn re-evaluated.    98     99 print get_using(f(C, 0), c)(2)  # 2   100    101 try:   102     print g(C, 1)               # should fail with an error caused by a guard   103 except TypeError:   104     print "g(C, 1): C is not a suitable argument."   105    106 print g(c, 1)                   # 1   107 print g(c, 0)(3)                # 3   108    109 print h(c, getc)                # 1   110 print h(c, 0)(4)                # 4   111    112 try:   113     print h(c, getd)            # should fail with an error caused by a guard   114 except TypeError:   115     print "h(c, getd): getd provides an unsuitable result."   116    117 try:   118     print h(d, 0)(4)            # should fail with an error caused by a test   119 except TypeError:   120     print "h(d, 0): d is not a suitable argument."   121    122 try:   123     print g(c, 1)(5)   124 except TypeError:   125     print "g(c, 1)(5): attempt to invoke an integer result from g."