why does py_compile.compile() miss some errors in sourcefile?

Bengt Richter bokr at oz.net
Mon Dec 29 04:00:36 EST 2003


On 28 Dec 2003 23:16:18 -0800, fBechmann at web.de (Frank Bechmann) wrote:

>where can I find some documentation, which errors will be found by
>'py_compile.compile' and which will not be found.
>
># t1.py
># =====
>
>import os.path
>import py_compile
>
>py_compile.compile(os.path.join(os.path.dirname(__file__), "t2.py"),
>                    doraise=True)
>
>
># t2.py
># =====
># following line is found as an error:
># Class C:  # <== 'SyntaxError: invalid syntax'
>
>class C:
>    pass
>
>c = CC()    # <== not found as an error from py_compile
>            #   but found as an error from python-executable:
>            #   'NameError: name 'CC' is not defined'
>
The difference is between compiling and executing. Syntax errors are found
during complilation and run-time errors during execution ;-) py_compile apparently
does not execute the code it compiles.

c = CC()

compiles ok. It just says, look up CC in the directory associated with the code excution,
call it, and bind the result to c. There is no error until you try to execute it, and
actually try to look up CC. With py_compile you don't have a reasonable way to interfere
before execution, to supply a CC, but if you compile interactively you can, e.g.,

 >>> code = compile('c = CC()','','single')
 >>> exec code
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "", line 1, in ?
 NameError: name 'CC' is not defined

But we could have done this before executing:

 >>> def CC(): print 'Hello from CC'; return 'CC result'
 ...
 >>> exec code
 Hello from CC
 >>> c
 'CC result'

In general, the compiler can't know if you
are going to fix things up before execution.

If you import or execfile, you will be executing the code (at least on
the first import -- if you're not the first, no re-execution). Import will
create it's own global name space to execute in (and thus to look for CC in),
so CC won't be there, but with execfile you could specify a directory that already
has CC defined in it, and it should succeed. E.g., using your t2.py:

print it to make sure:

 >>> print '===< t2.py >===\n%s======'%file('t2.py').read()
 ===< t2.py >===
 # =====
 # following line is found as an error:
 # Class C:  # <== 'SyntaxError: invalid syntax' 

 class C:
     pass

 c = CC()    # <== not found as an error from py_compile
             #   but found as an error from python-executable:
             #   'NameError: name 'CC' is not defined'

 ======

We set up a directory
 >>> d = {}

define a funtion
 >>> def foo(): print 'This is foo, bound to CC in dict d'; return 'foo/CC result'
 ...

bind it to CC in the directory, which will be the global name space for the execution
 >>> d['CC']=foo

check on it
 >>> d
 {'CC': <function foo at 0x008FDF70>}

execute t2.py in it
 >>> execfile('t2.py', d)
 This is foo, bound to CC in dict d

we note the side effect printed
and check on d again (just the names, I know what's coming ;-)

 >>> d.keys()
 ['CC', '__builtins__', 'C', 'c']
The __builtins__ key is put there as a side effect of execfile.

we can check on that "c = CC()" assignment result:
 >>> d['c']
 'foo/CC result'

HTH

Regards,
Bengt Richter




More information about the Python-list mailing list