[Python-Dev] confusing exec error message in 3.0

Steven D'Aprano steve at pearwood.info
Thu Aug 28 03:21:15 CEST 2008


On Thu, 28 Aug 2008 08:39:01 am Georg Brandl wrote:
> Fredrik Lundh schrieb:
> > (using 3.0a4)
> >
> >  >>> exec(open("file.py"))
> >
> > Traceback (most recent call last):
> >    File "<stdin>", line 1, in <module>
> > TypeError: exec() arg 1 must be a string, file, or code object, not
> > TextIOWrapper
> >
> > so what's "file" referring to here?
> >
> > (the above works under 2.5, of course)
>
> See http://bugs.python.org/issue1762972 -- it has been decided to
> drop that possibility.

Hmmm... I have a concern with one of the patches in that issue; I refer 
to patch that changes the semantics of module's __file__ attribute.

Guido noted that exec(open(M.__file__).read(), M.__dict__) almost worked 
as a replacement for reload(), except that there were issues with file 
extensions (.py, .pyc, .pyo and even things like .pyc24). So it was 
decided that M.__file__ should always point to the source file.

But now that reload() is now moved into the imp module, I don't see that 
the justification for changing the semantics of M.__file__ still 
exists. imp.reload(M) is much better for interactive use than 
exec(open(M.__file__).read(), M.__dict__).

Is there still a justification for having M.__file__ point to the source 
even if the module was actually loaded from the .pyc version? If so, 
what is that?

Some years ago, as a newbie, I was having trouble with reload() 
repeatedly not picking up changes I was making to a module. The problem 
turned out to be user-error, but how I discovered that was by looking 
at M.__file__ and noticing that Python was loading the .pyc file 
instead of the .py file I was expecting. Had M.__file__ given 
misleading information, I would have been mislead for much longer. 
Here's a small contrived example under Python 2.5:

>>> import parrot
>>> parrot.__file__
'parrot.py'
>>> # pretend that I made changes to the source 
... # in my editor, but forgot to save them
... reload(parrot)
<module 'parrot' from 'parrot.pyc'>
>>> parrot.__file__
'parrot.pyc'


I don't think M.__file__ should lie and say it was loaded from a file 
that it wasn't loaded from. It's useful to be able to look at a module 
and see what file it was actually loaded from.



-- 
Steven


More information about the Python-Dev mailing list