1import unittest
2import sys
3import _ast
4from test import test_support
5import textwrap
6
7class TestSpecifics(unittest.TestCase):
8
9    def test_no_ending_newline(self):
10        compile("hi", "<test>", "exec")
11        compile("hi\r", "<test>", "exec")
12
13    def test_empty(self):
14        compile("", "<test>", "exec")
15
16    def test_other_newlines(self):
17        compile("\r\n", "<test>", "exec")
18        compile("\r", "<test>", "exec")
19        compile("hi\r\nstuff\r\ndef f():\n    pass\r", "<test>", "exec")
20        compile("this_is\rreally_old_mac\rdef f():\n    pass", "<test>", "exec")
21
22    def test_debug_assignment(self):
23        # catch assignments to __debug__
24        self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
25        import __builtin__
26        prev = __builtin__.__debug__
27        setattr(__builtin__, '__debug__', 'sure')
28        setattr(__builtin__, '__debug__', prev)
29
30    def test_argument_handling(self):
31        # detect duplicate positional and keyword arguments
32        self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
33        self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
34        self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
35        try:
36            exec 'def f(a, a): pass'
37            self.fail("duplicate arguments")
38        except SyntaxError:
39            pass
40        try:
41            exec 'def f(a = 0, a = 1): pass'
42            self.fail("duplicate keyword arguments")
43        except SyntaxError:
44            pass
45        try:
46            exec 'def f(a): global a; a = 1'
47            self.fail("variable is global and local")
48        except SyntaxError:
49            pass
50
51    def test_syntax_error(self):
52        self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
53
54    def test_none_keyword_arg(self):
55        self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
56
57    def test_duplicate_global_local(self):
58        try:
59            exec 'def f(a): global a; a = 1'
60            self.fail("variable is global and local")
61        except SyntaxError:
62            pass
63
64    def test_exec_functional_style(self):
65        # Exec'ing a tuple of length 2 works.
66        g = {'b': 2}
67        exec("a = b + 1", g)
68        self.assertEqual(g['a'], 3)
69
70        # As does exec'ing a tuple of length 3.
71        l = {'b': 3}
72        g = {'b': 5, 'c': 7}
73        exec("a = b + c", g, l)
74        self.assertNotIn('a', g)
75        self.assertEqual(l['a'], 10)
76
77        # Tuples not of length 2 or 3 are invalid.
78        with self.assertRaises(TypeError):
79            exec("a = b + 1",)
80
81        with self.assertRaises(TypeError):
82            exec("a = b + 1", {}, {}, {})
83
84        # Can't mix and match the two calling forms.
85        g = {'a': 3, 'b': 4}
86        l = {}
87        with self.assertRaises(TypeError):
88            exec("a = b + 1", g) in g
89        with self.assertRaises(TypeError):
90            exec("a = b + 1", g, l) in g, l
91
92    def test_exec_with_general_mapping_for_locals(self):
93
94        class M:
95            "Test mapping interface versus possible calls from eval()."
96            def __getitem__(self, key):
97                if key == 'a':
98                    return 12
99                raise KeyError
100            def __setitem__(self, key, value):
101                self.results = (key, value)
102            def keys(self):
103                return list('xyz')
104
105        m = M()
106        g = globals()
107        exec 'z = a' in g, m
108        self.assertEqual(m.results, ('z', 12))
109        try:
110            exec 'z = b' in g, m
111        except NameError:
112            pass
113        else:
114            self.fail('Did not detect a KeyError')
115        exec 'z = dir()' in g, m
116        self.assertEqual(m.results, ('z', list('xyz')))
117        exec 'z = globals()' in g, m
118        self.assertEqual(m.results, ('z', g))
119        exec 'z = locals()' in g, m
120        self.assertEqual(m.results, ('z', m))
121        try:
122            exec 'z = b' in m
123        except TypeError:
124            pass
125        else:
126            self.fail('Did not validate globals as a real dict')
127
128        class A:
129            "Non-mapping"
130            pass
131        m = A()
132        try:
133            exec 'z = a' in g, m
134        except TypeError:
135            pass
136        else:
137            self.fail('Did not validate locals as a mapping')
138
139        # Verify that dict subclasses work as well
140        class D(dict):
141            def __getitem__(self, key):
142                if key == 'a':
143                    return 12
144                return dict.__getitem__(self, key)
145        d = D()
146        exec 'z = a' in g, d
147        self.assertEqual(d['z'], 12)
148
149    def test_extended_arg(self):
150        longexpr = 'x = x or ' + '-x' * 2500
151        code = '''
152def f(x):
153    %s
154    %s
155    %s
156    %s
157    %s
158    %s
159    %s
160    %s
161    %s
162    %s
163    # the expressions above have no effect, x == argument
164    while x:
165        x -= 1
166        # EXTENDED_ARG/JUMP_ABSOLUTE here
167    return x
168''' % ((longexpr,)*10)
169        exec code
170        self.assertEqual(f(5), 0)
171
172    def test_complex_args(self):
173
174        with test_support.check_py3k_warnings(
175                ("tuple parameter unpacking has been removed", SyntaxWarning)):
176            exec textwrap.dedent('''
177        def comp_args((a, b)):
178            return a,b
179        self.assertEqual(comp_args((1, 2)), (1, 2))
180
181        def comp_args((a, b)=(3, 4)):
182            return a, b
183        self.assertEqual(comp_args((1, 2)), (1, 2))
184        self.assertEqual(comp_args(), (3, 4))
185
186        def comp_args(a, (b, c)):
187            return a, b, c
188        self.assertEqual(comp_args(1, (2, 3)), (1, 2, 3))
189
190        def comp_args(a=2, (b, c)=(3, 4)):
191            return a, b, c
192        self.assertEqual(comp_args(1, (2, 3)), (1, 2, 3))
193        self.assertEqual(comp_args(), (2, 3, 4))
194        ''')
195
196    def test_argument_order(self):
197        try:
198            exec 'def f(a=1, (b, c)): pass'
199            self.fail("non-default args after default")
200        except SyntaxError:
201            pass
202
203    def test_float_literals(self):
204        # testing bad float literals
205        self.assertRaises(SyntaxError, eval, "2e")
206        self.assertRaises(SyntaxError, eval, "2.0e+")
207        self.assertRaises(SyntaxError, eval, "1e-")
208        self.assertRaises(SyntaxError, eval, "3-4e/21")
209
210    def test_indentation(self):
211        # testing compile() of indented block w/o trailing newline"
212        s = """
213if 1:
214    if 2:
215        pass"""
216        compile(s, "<string>", "exec")
217
218    # This test is probably specific to CPython and may not generalize
219    # to other implementations.  We are trying to ensure that when
220    # the first line of code starts after 256, correct line numbers
221    # in tracebacks are still produced.
222    def test_leading_newlines(self):
223        s256 = "".join(["\n"] * 256 + ["spam"])
224        co = compile(s256, 'fn', 'exec')
225        self.assertEqual(co.co_firstlineno, 257)
226        self.assertEqual(co.co_lnotab, '')
227
228    def test_literals_with_leading_zeroes(self):
229        for arg in ["077787", "0xj", "0x.", "0e",  "090000000000000",
230                    "080000000000000", "000000000000009", "000000000000008",
231                    "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
232                    "0b101j2", "0o153j2", "0b100e1", "0o777e1", "0o8", "0o78"]:
233            self.assertRaises(SyntaxError, eval, arg)
234
235        self.assertEqual(eval("0777"), 511)
236        self.assertEqual(eval("0777L"), 511)
237        self.assertEqual(eval("000777"), 511)
238        self.assertEqual(eval("0xff"), 255)
239        self.assertEqual(eval("0xffL"), 255)
240        self.assertEqual(eval("0XfF"), 255)
241        self.assertEqual(eval("0777."), 777)
242        self.assertEqual(eval("0777.0"), 777)
243        self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
244        self.assertEqual(eval("0777e1"), 7770)
245        self.assertEqual(eval("0e0"), 0)
246        self.assertEqual(eval("0000E-012"), 0)
247        self.assertEqual(eval("09.5"), 9.5)
248        self.assertEqual(eval("0777j"), 777j)
249        self.assertEqual(eval("00j"), 0j)
250        self.assertEqual(eval("00.0"), 0)
251        self.assertEqual(eval("0e3"), 0)
252        self.assertEqual(eval("090000000000000."), 90000000000000.)
253        self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
254        self.assertEqual(eval("090000000000000e0"), 90000000000000.)
255        self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
256        self.assertEqual(eval("090000000000000j"), 90000000000000j)
257        self.assertEqual(eval("000000000000007"), 7)
258        self.assertEqual(eval("000000000000008."), 8.)
259        self.assertEqual(eval("000000000000009."), 9.)
260        self.assertEqual(eval("0b101010"), 42)
261        self.assertEqual(eval("-0b000000000010"), -2)
262        self.assertEqual(eval("0o777"), 511)
263        self.assertEqual(eval("-0o0000010"), -8)
264        self.assertEqual(eval("020000000000.0"), 20000000000.0)
265        self.assertEqual(eval("037777777777e0"), 37777777777.0)
266        self.assertEqual(eval("01000000000000000000000.0"),
267                         1000000000000000000000.0)
268
269    def test_unary_minus(self):
270        # Verify treatment of unary minus on negative numbers SF bug #660455
271        if sys.maxint == 2147483647:
272            # 32-bit machine
273            all_one_bits = '0xffffffff'
274            self.assertEqual(eval(all_one_bits), 4294967295L)
275            self.assertEqual(eval("-" + all_one_bits), -4294967295L)
276        elif sys.maxint == 9223372036854775807:
277            # 64-bit machine
278            all_one_bits = '0xffffffffffffffff'
279            self.assertEqual(eval(all_one_bits), 18446744073709551615L)
280            self.assertEqual(eval("-" + all_one_bits), -18446744073709551615L)
281        else:
282            self.fail("How many bits *does* this machine have???")
283        # Verify treatment of constant folding on -(sys.maxint+1)
284        # i.e. -2147483648 on 32 bit platforms.  Should return int, not long.
285        self.assertIsInstance(eval("%s" % (-sys.maxint - 1)), int)
286        self.assertIsInstance(eval("%s" % (-sys.maxint - 2)), long)
287
288    if sys.maxint == 9223372036854775807:
289        def test_32_63_bit_values(self):
290            a = +4294967296  # 1 << 32
291            b = -4294967296  # 1 << 32
292            c = +281474976710656  # 1 << 48
293            d = -281474976710656  # 1 << 48
294            e = +4611686018427387904  # 1 << 62
295            f = -4611686018427387904  # 1 << 62
296            g = +9223372036854775807  # 1 << 63 - 1
297            h = -9223372036854775807  # 1 << 63 - 1
298
299            for variable in self.test_32_63_bit_values.func_code.co_consts:
300                if variable is not None:
301                    self.assertIsInstance(variable, int)
302
303    def test_sequence_unpacking_error(self):
304        # Verify sequence packing/unpacking with "or".  SF bug #757818
305        i,j = (1, -1) or (-1, 1)
306        self.assertEqual(i, 1)
307        self.assertEqual(j, -1)
308
309    def test_none_assignment(self):
310        stmts = [
311            'None = 0',
312            'None += 0',
313            '__builtins__.None = 0',
314            'def None(): pass',
315            'class None: pass',
316            '(a, None) = 0, 0',
317            'for None in range(10): pass',
318            'def f(None): pass',
319            'import None',
320            'import x as None',
321            'from x import None',
322            'from x import y as None'
323        ]
324        for stmt in stmts:
325            stmt += "\n"
326            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
327            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
328        # This is ok.
329        compile("from None import x", "tmp", "exec")
330        compile("from x import None as y", "tmp", "exec")
331        compile("import None as x", "tmp", "exec")
332
333    def test_import(self):
334        succeed = [
335            'import sys',
336            'import os, sys',
337            'import os as bar',
338            'import os.path as bar',
339            'from __future__ import nested_scopes, generators',
340            'from __future__ import (nested_scopes,\ngenerators)',
341            'from __future__ import (nested_scopes,\ngenerators,)',
342            'from sys import stdin, stderr, stdout',
343            'from sys import (stdin, stderr,\nstdout)',
344            'from sys import (stdin, stderr,\nstdout,)',
345            'from sys import (stdin\n, stderr, stdout)',
346            'from sys import (stdin\n, stderr, stdout,)',
347            'from sys import stdin as si, stdout as so, stderr as se',
348            'from sys import (stdin as si, stdout as so, stderr as se)',
349            'from sys import (stdin as si, stdout as so, stderr as se,)',
350            ]
351        fail = [
352            'import (os, sys)',
353            'import (os), (sys)',
354            'import ((os), (sys))',
355            'import (sys',
356            'import sys)',
357            'import (os,)',
358            'import os As bar',
359            'import os.path a bar',
360            'from sys import stdin As stdout',
361            'from sys import stdin a stdout',
362            'from (sys) import stdin',
363            'from __future__ import (nested_scopes',
364            'from __future__ import nested_scopes)',
365            'from __future__ import nested_scopes,\ngenerators',
366            'from sys import (stdin',
367            'from sys import stdin)',
368            'from sys import stdin, stdout,\nstderr',
369            'from sys import stdin si',
370            'from sys import stdin,'
371            'from sys import (*)',
372            'from sys import (stdin,, stdout, stderr)',
373            'from sys import (stdin, stdout),',
374            ]
375        for stmt in succeed:
376            compile(stmt, 'tmp', 'exec')
377        for stmt in fail:
378            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
379
380    def test_for_distinct_code_objects(self):
381        # SF bug 1048870
382        def f():
383            f1 = lambda x=1: x
384            f2 = lambda x=2: x
385            return f1, f2
386        f1, f2 = f()
387        self.assertNotEqual(id(f1.func_code), id(f2.func_code))
388
389    def test_lambda_doc(self):
390        l = lambda: "foo"
391        self.assertIsNone(l.__doc__)
392
393    def test_unicode_encoding(self):
394        code = u"# -*- coding: utf-8 -*-\npass\n"
395        self.assertRaises(SyntaxError, compile, code, "tmp", "exec")
396
397    def test_subscripts(self):
398        # SF bug 1448804
399        # Class to make testing subscript results easy
400        class str_map(object):
401            def __init__(self):
402                self.data = {}
403            def __getitem__(self, key):
404                return self.data[str(key)]
405            def __setitem__(self, key, value):
406                self.data[str(key)] = value
407            def __delitem__(self, key):
408                del self.data[str(key)]
409            def __contains__(self, key):
410                return str(key) in self.data
411        d = str_map()
412        # Index
413        d[1] = 1
414        self.assertEqual(d[1], 1)
415        d[1] += 1
416        self.assertEqual(d[1], 2)
417        del d[1]
418        self.assertNotIn(1, d)
419        # Tuple of indices
420        d[1, 1] = 1
421        self.assertEqual(d[1, 1], 1)
422        d[1, 1] += 1
423        self.assertEqual(d[1, 1], 2)
424        del d[1, 1]
425        self.assertNotIn((1, 1), d)
426        # Simple slice
427        d[1:2] = 1
428        self.assertEqual(d[1:2], 1)
429        d[1:2] += 1
430        self.assertEqual(d[1:2], 2)
431        del d[1:2]
432        self.assertNotIn(slice(1, 2), d)
433        # Tuple of simple slices
434        d[1:2, 1:2] = 1
435        self.assertEqual(d[1:2, 1:2], 1)
436        d[1:2, 1:2] += 1
437        self.assertEqual(d[1:2, 1:2], 2)
438        del d[1:2, 1:2]
439        self.assertNotIn((slice(1, 2), slice(1, 2)), d)
440        # Extended slice
441        d[1:2:3] = 1
442        self.assertEqual(d[1:2:3], 1)
443        d[1:2:3] += 1
444        self.assertEqual(d[1:2:3], 2)
445        del d[1:2:3]
446        self.assertNotIn(slice(1, 2, 3), d)
447        # Tuple of extended slices
448        d[1:2:3, 1:2:3] = 1
449        self.assertEqual(d[1:2:3, 1:2:3], 1)
450        d[1:2:3, 1:2:3] += 1
451        self.assertEqual(d[1:2:3, 1:2:3], 2)
452        del d[1:2:3, 1:2:3]
453        self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d)
454        # Ellipsis
455        d[...] = 1
456        self.assertEqual(d[...], 1)
457        d[...] += 1
458        self.assertEqual(d[...], 2)
459        del d[...]
460        self.assertNotIn(Ellipsis, d)
461        # Tuple of Ellipses
462        d[..., ...] = 1
463        self.assertEqual(d[..., ...], 1)
464        d[..., ...] += 1
465        self.assertEqual(d[..., ...], 2)
466        del d[..., ...]
467        self.assertNotIn((Ellipsis, Ellipsis), d)
468
469    def test_mangling(self):
470        class A:
471            def f():
472                __mangled = 1
473                __not_mangled__ = 2
474                import __mangled_mod
475                import __package__.module
476
477        self.assertIn("_A__mangled", A.f.func_code.co_varnames)
478        self.assertIn("__not_mangled__", A.f.func_code.co_varnames)
479        self.assertIn("_A__mangled_mod", A.f.func_code.co_varnames)
480        self.assertIn("__package__", A.f.func_code.co_varnames)
481
482    def test_compile_ast(self):
483        fname = __file__
484        if fname.lower().endswith(('pyc', 'pyo')):
485            fname = fname[:-1]
486        with open(fname, 'r') as f:
487            fcontents = f.read()
488        sample_code = [
489            ['<assign>', 'x = 5'],
490            ['<print1>', 'print 1'],
491            ['<printv>', 'print v'],
492            ['<printTrue>', 'print True'],
493            ['<printList>', 'print []'],
494            ['<ifblock>', """if True:\n    pass\n"""],
495            ['<forblock>', """for n in [1, 2, 3]:\n    print n\n"""],
496            ['<deffunc>', """def foo():\n    pass\nfoo()\n"""],
497            [fname, fcontents],
498        ]
499
500        for fname, code in sample_code:
501            co1 = compile(code, '%s1' % fname, 'exec')
502            ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
503            self.assertTrue(type(ast) == _ast.Module)
504            co2 = compile(ast, '%s3' % fname, 'exec')
505            self.assertEqual(co1, co2)
506            # the code object's filename comes from the second compilation step
507            self.assertEqual(co2.co_filename, '%s3' % fname)
508
509        # raise exception when node type doesn't match with compile mode
510        co1 = compile('print 1', '<string>', 'exec', _ast.PyCF_ONLY_AST)
511        self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
512
513        # raise exception when node type is no start node
514        self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
515
516        # raise exception when node has invalid children
517        ast = _ast.Module()
518        ast.body = [_ast.BoolOp()]
519        self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
520
521
522def test_main():
523    test_support.run_unittest(TestSpecifics)
524
525if __name__ == "__main__":
526    test_main()
527