test_scope.py revision 5941d191deaf2a0c8eab5ce75316067ed16dfb1a
1from __future__ import nested_scopes
2
3from test.test_support import verify, TestFailed, check_syntax
4
5print "1. simple nesting"
6
7def make_adder(x):
8    def adder(y):
9        return x + y
10    return adder
11
12inc = make_adder(1)
13plus10 = make_adder(10)
14
15verify(inc(1) == 2)
16verify(plus10(-2) == 8)
17
18print "2. extra nesting"
19
20def make_adder2(x):
21    def extra(): # check freevars passing through non-use scopes
22        def adder(y):
23            return x + y
24        return adder
25    return extra()
26
27inc = make_adder2(1)
28plus10 = make_adder2(10)
29
30verify(inc(1) == 2)
31verify(plus10(-2) == 8)
32
33print "3. simple nesting + rebinding"
34
35def make_adder3(x):
36    def adder(y):
37        return x + y
38    x = x + 1 # check tracking of assignment to x in defining scope
39    return adder
40
41inc = make_adder3(0)
42plus10 = make_adder3(9)
43
44verify(inc(1) == 2)
45verify(plus10(-2) == 8)
46
47print "4. nesting with global but no free"
48
49def make_adder4(): # XXX add exta level of indirection
50    def nest():
51        def nest():
52            def adder(y):
53                return global_x + y # check that plain old globals work
54            return adder
55        return nest()
56    return nest()
57
58global_x = 1
59adder = make_adder4()
60verify(adder(1) == 2)
61
62global_x = 10
63verify(adder(-2) == 8)
64
65print "5. nesting through class"
66
67def make_adder5(x):
68    class Adder:
69        def __call__(self, y):
70            return x + y
71    return Adder()
72
73inc = make_adder5(1)
74plus10 = make_adder5(10)
75
76verify(inc(1) == 2)
77verify(plus10(-2) == 8)
78
79print "6. nesting plus free ref to global"
80
81def make_adder6(x):
82    global global_nest_x
83    def adder(y):
84        return global_nest_x + y
85    global_nest_x = x
86    return adder
87
88inc = make_adder6(1)
89plus10 = make_adder6(10)
90
91verify(inc(1) == 11) # there's only one global
92verify(plus10(-2) == 8)
93
94print "7. nearest enclosing scope"
95
96def f(x):
97    def g(y):
98        x = 42 # check that this masks binding in f()
99        def h(z):
100            return x + z
101        return h
102    return g(2)
103
104test_func = f(10)
105verify(test_func(5) == 47)
106
107print "8. mixed freevars and cellvars"
108
109def identity(x):
110    return x
111
112def f(x, y, z):
113    def g(a, b, c):
114        a = a + x # 3
115        def h():
116            # z * (4 + 9)
117            # 3 * 13
118            return identity(z * (b + y))
119        y = c + z # 9
120        return h
121    return g
122
123g = f(1, 2, 3)
124h = g(2, 4, 6)
125verify(h() == 39)
126
127print "9. free variable in method"
128
129def test():
130    method_and_var = "var"
131    class Test:
132        def method_and_var(self):
133            return "method"
134        def test(self):
135            return method_and_var
136        def actual_global(self):
137            return str("global")
138        def str(self):
139            return str(self)
140    return Test()
141
142t = test()
143verify(t.test() == "var")
144verify(t.method_and_var() == "method")
145verify(t.actual_global() == "global")
146
147method_and_var = "var"
148class Test:
149    # this class is not nested, so the rules are different
150    def method_and_var(self):
151        return "method"
152    def test(self):
153        return method_and_var
154    def actual_global(self):
155        return str("global")
156    def str(self):
157        return str(self)
158
159t = Test()
160verify(t.test() == "var")
161verify(t.method_and_var() == "method")
162verify(t.actual_global() == "global")
163
164print "10. recursion"
165
166def f(x):
167    def fact(n):
168        if n == 0:
169            return 1
170        else:
171            return n * fact(n - 1)
172    if x >= 0:
173        return fact(x)
174    else:
175        raise ValueError, "x must be >= 0"
176
177verify(f(6) == 720)
178
179
180print "11. unoptimized namespaces"
181
182check_syntax("""from __future__ import nested_scopes
183def unoptimized_clash1(strip):
184    def f(s):
185        from string import *
186        return strip(s) # ambiguity: free or local
187    return f
188""")
189
190check_syntax("""from __future__ import nested_scopes
191def unoptimized_clash2():
192    from string import *
193    def f(s):
194        return strip(s) # ambiguity: global or local
195    return f
196""")
197
198check_syntax("""from __future__ import nested_scopes
199def unoptimized_clash2():
200    from string import *
201    def g():
202        def f(s):
203            return strip(s) # ambiguity: global or local
204        return f
205""")
206
207# XXX could allow this for exec with const argument, but what's the point
208check_syntax("""from __future__ import nested_scopes
209def error(y):
210    exec "a = 1"
211    def f(x):
212        return x + y
213    return f
214""")
215
216check_syntax("""from __future__ import nested_scopes
217def f(x):
218    def g():
219        return x
220    del x # can't del name
221""")
222
223check_syntax("""from __future__ import nested_scopes
224def f():
225    def g():
226         from string import *
227         return strip # global or local?
228""")
229
230# and verify a few cases that should work
231
232def noproblem1():
233    from string import *
234    f = lambda x:x
235
236def noproblem2():
237    from string import *
238    def f(x):
239        return x + 1
240
241def noproblem3():
242    from string import *
243    def f(x):
244        global y
245        y = x
246
247print "12. lambdas"
248
249f1 = lambda x: lambda y: x + y
250inc = f1(1)
251plus10 = f1(10)
252verify(inc(1) == 2)
253verify(plus10(5) == 15)
254
255f2 = lambda x: (lambda : lambda y: x + y)()
256inc = f2(1)
257plus10 = f2(10)
258verify(inc(1) == 2)
259verify(plus10(5) == 15)
260
261f3 = lambda x: lambda y: global_x + y
262global_x = 1
263inc = f3(None)
264verify(inc(2) == 3)
265
266f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
267g = f8(1, 2, 3)
268h = g(2, 4, 6)
269verify(h() == 18)
270
271print "13. UnboundLocal"
272
273def errorInOuter():
274    print y
275    def inner():
276        return y
277    y = 1
278
279def errorInInner():
280    def inner():
281        return y
282    inner()
283    y = 1
284
285try:
286    errorInOuter()
287except UnboundLocalError:
288    pass
289else:
290    raise TestFailed
291
292try:
293    errorInInner()
294except UnboundLocalError:
295    pass
296else:
297    raise TestFailed
298
299print "14. complex definitions"
300
301def makeReturner(*lst):
302    def returner():
303        return lst
304    return returner
305
306verify(makeReturner(1,2,3)() == (1,2,3))
307
308def makeReturner2(**kwargs):
309    def returner():
310        return kwargs
311    return returner
312
313verify(makeReturner2(a=11)()['a'] == 11)
314
315def makeAddPair((a, b)):
316    def addPair((c, d)):
317        return (a + c, b + d)
318    return addPair
319
320verify(makeAddPair((1, 2))((100, 200)) == (101,202))
321