classification
Title: Regression for executing packages
Type: behavior Stage:
Components: Interpreter Core Versions: Python 2.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: ncoghlan Nosy List: barry, benjamin.peterson, illume, ncoghlan
Priority: critical Keywords:

Created on 2008-05-04 00:36 by benjamin.peterson, last changed 2009-07-10 09:08 by ncoghlan. This issue is now closed.

Messages (7)
msg66184 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-05-04 00:36
If I have a package like this:

pack/
    __init__.py

and __init__.py looks like this
if __name__ == "__main__":
    print "Spam"

python -m pack gives
one is a package and cannot be directly executed

This is regression from 2.5 where "Spam" would be printed.
msg66189 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2008-05-04 04:34
The ability to execute packages was never intended, since doing so
breaks imports in a variety of subtle ways. It was actually a bug in 2.5
that it was permitted at all, so 2.6 not only disabled it again, but
also added a test to make sure it stays disabled (2.4 correctly rejected
it with an ImportError, just as 2.6 does).

Here's the relevant svn log entry:

r56509 | nick.coghlan | 2007-07-23 23:41:45 +1000 (Mon, 23 Jul 2007) | 5
lines

Correctly cleanup sys.modules after executing runpy relative import
tests
Restore Python 2.4 ImportError when attempting to execute a package
(as imports cannot be guaranteed to work properly if you try it)
msg74678 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2008-10-13 09:20
(Adding some additional details regarding the reasons why this became an
error again in 2.6)

The ImportError when attempting to execute a package was lost during the
conversion from the C-based implementation in 2.4 to the runpy module
based implementation as part of 2.5. Packages really aren't meant to be
executable with -m - it gets messy since__init__ is able to modify the
way module lookups work within the package, and there are various other
package specific details related to relative imports that don't apply
when dealing with normal modules.

That said, executing "-m pkg.__init__" with Python 2.6 will generally
have the same effect as doing "-m pkg" with Python 2.5 (it keeps the
import machinery happy since the package gets imported normally first,
and so long as pkg.__init__ can cope with being first imported normally
for the package initialisation and then run as '__main__' it should also
work as a script).

Anyone that would like to see the ability to execute packages restored
should feel free to create a RFE issue for it, but it would take a
fairly detailed analysis of the import system to convince me that doing
so doesn't break any of the interpreter internals.
msg90370 - (view) Author: Rene Dudfield (illume) Date: 2009-07-10 02:52
Hi,

note -m on packages still works with python3.0 and python3.1.  It works
by allowing a __main__.py file that gets called by -m.

This is a really annoying regression for python2.6.  It's a fairly wide
spread feature too.

I can't see any PEP for why this regression exists.

For pygame we will probably work around it by using "python -m
tests.main" or "python -m pygame.tests.run" which is ugly, but at least
it'll work!


cheers,
msg90372 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2009-07-10 03:30
It doesn't work in 2.6 or 3.0 because, as stated above, it was only due
to a bug that it even appeared to work at all in 2.5 (it was always
meant to be disallowed because it puts dodgy data in the import
machinery's internal records if you do it).

It took a new feature (looking for a __main__ module as described in
issue 4195 and as you already noted) to make it actually work properly
for 3.1 (and 2.7 when that is released).
msg90375 - (view) Author: Rene Dudfield (illume) Date: 2009-07-10 05:21
hello,

thanks for the explanation of why it's that way.  

Any ideas of a work around?


python2.5 has been out for ages now. Even if it was an accident, it's
the behavior people expect, and it's still a regression.

Also, why should it matter if a module is a package or a module?

Note how pygame.tests has a type of module, and not of package:
>>> import pygame.tests
>>> type(pygame.tests)
<type 'module'>

Even though it is a package, python calls its type a module.  This has
been true for a long time (at least as far back as python2.3).

Because it's a regression, I think this bug should be reopened.


To illustrate why it causes problems, here is part of the documentation
mentioning the __main__.


"""
You can do a self test with:
    python -m pygame.tests
Or with python2.6 do:
    python -m pygame.tests.__main__

See a list of examples...
  python -m pygame.examples
Or with python2.6,
  python -m pygame.examples.__main__
"""

It's twice as long, and I doubt anyone will remember the __main__ part.


People used to running their programs with -m now have broken programs
with python2.6.


Having said all that, maybe there is a work around...

One work around might be to make it into a module-module, not a
package-module.  Then have the module-module load the package-module
into its namespace.  I haven't tested that yet, but it might work.  Will
have to go through a round of testing to see how that works out.  Will
write back when I've found out the issues with that approach.


cheers,
msg90380 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2009-07-10 09:07
If you need to support Python 2.6 as well as 3.1, the simplest thing to
do is just tell people to run "pygame.tests.main" always (i.e.
completely skip the idea of executing the package directly and always
run a submodule instead).

The reason the distinction between packages and modules matters is that
the import system has to do more bookkeeping for packages (since they
can contain modules and subpackages). Direct execution of packages was
meant to be disallowed because the Python 2.5 accident means the
__init__ module runs without that extra bookkeeping having been set up
properly, which can lead to a broken import system. Unfortunately, the
relevant error message was lost for 2.5 in a refactoring that merged
duplicated code from a couple of different parts of the standard library.

I added Barry to the nosy list as the 2.6 release manager. I'm reluctant
to re-enable a known-broken behaviour at all, but if Barry thinks it
would be worthwhile downgrading this to a DeprecationWarning rather than
an outright error in the next 2.6 maintenance then I would be willing to
do that. That would still leave you with people getting a warning
though, so I don't think it would be that much of a gain in practice.
History
Date User Action Args
2009-07-10 09:08:01ncoghlansetnosy: + barry
messages: + msg90380
2009-07-10 05:21:41illumesetmessages: + msg90375
2009-07-10 03:30:52ncoghlansetmessages: + msg90372
2009-07-10 02:52:44illumesetnosy: + illume
messages: + msg90370
2008-10-13 09:20:14ncoghlansetmessages: + msg74678
2008-05-04 04:34:26ncoghlansetstatus: open -> closed
resolution: not a bug
messages: + msg66189
2008-05-04 00:40:15benjamin.petersonsetassignee: ncoghlan
nosy: + ncoghlan
2008-05-04 00:36:17benjamin.petersoncreate