Author eric.snow
Recipients eric.snow, ncoghlan
Date 2011-11-25.08:52:59
SpamBayes Score 3.33067e-16
Marked as misclassified No
Message-id <1322211181.82.0.909365539545.issue13475@psf.upfronthosting.co.za>
In-reply-to
Content
The current behavior is an implicit "-p .", which causes all sorts of hard-to-figure-out problems, most of which PEP 395 is rightly trying to fix.  I'm suggesting that the next step would be to make "--nopath0" the default (rendering the flag unnecessary).  Since this changes the status quo, I'll try to make the case here that it's worth it.

---

First of all, the current implicit sys.path[0] initialization for scripts has been around since forever.  Why would we change it now?  The inspiration is three-fold: we _said_ we got rid of implicit relative imports already, PEP 395 already has made a case for changing the status quo (though not to this degree), and a "-p" flag provides a simple mechanism to get the current behavior explicitly.

Like Nick says in PEP 395, "PEP 328 eliminated implicit relative imports from imported modules. This PEP proposes that the de facto implicit relative imports from main modules that are provided by the current initialisation behaviour for sys.path[0] also be eliminated."

I'm just saying we should go all the way, and that the "-p" flag would allow that.  As far as I can tell, there are two meaningful use cases for the currently implicit sys.path[0]:  When you are first _learning_ Python (not actually using it)...  When you are working on a new project...  Let's look at both, first relative to the currently implicit "-p .", then to the explicit site.

1. (current behavior) implicit sys.path[0] initialization

When a beginner is first learning Python, they learn at the interactive prompt or by running a single script.  Pretty quickly they learn about writing their own modules and using import to load them.

Where do the modules live?  In the CWD from which they are calling the Python executable.  The current implicit "-p ." means they can import their modules right there, and not have to learn yet about sys.path.  That's nice since they can concentrate their focus.

But later they _will_ run into hard-to-figure-out problems when they start relying on what are effectively implicit relative imports.  Or they will run into one of the problems that PEP 395 explains, which are likewise head-scratchers.  All of this can be pretty frustrating when you still don't know about things like the import machinery.

Consider how that beginner uses the implicit sys.path[0] behavior on a project, once they have some experience (hopefully I don't misrepresent something Nick explained to me).  The src/ directory of the project won't be under sys.path yet.  So to quickly test out their script, they change to src/ and run their script from there (something PEP 395 rightfully proposes fine-tuning).  They conveniently don't have to manually fiddle with sys.path.  That's a pretty neat trick.

The problem I have with this is that there's no difference between the sys.path workaround for the script and it's expected normal usage.  If you aren't aware of what's going on behind-the-scenes, you may end up with some confusing import exceptions later on.

2. explicit sys.path[0] initialization

With a -p flag, it's really easy to say "-p ." and get the previous implicit behavior.  Consider the impact on our beginner.  The try to run their script that imports modules in their CWD, but end up with an ImportError because we no longer have an implicit "-p .".

How is this an improvement?  No more mysterious default behavior.  There's only one way it will fail and it will fail the same way every time.  They'll learn pretty quickly (if not taught already) you have to use the -p flag if you want to import modules that aren't in the "standard" places.  The ImportError message, special-cased for imports in __main__, could help in that regard.

<aside>
As an aside, implicit or explicit "--nopath0", the path to the file for the failed import can really help in related situations.  Including it as an attribute on the ImportError, and especially in the error message, would rock.  See issue1559549.
</aside>

For the "src/" use-case, the developer won't be able to rely on the implicit behavior anymore.  A simple, explicit "-p ." fills the gap and makes it clear that they are doing something unusual.  On top of that, they can use -p with the path to the "src/" directory from anywhere and not have to change their directory.  All the better if -p takes advantage of the proposals in PEP 395.


In the end, this boils down to opt-in vs. opt-out.  Either you opt-in to the sys.path[0] initialization by using -p, or you opt-out of the default implicit "-p ." by passing "--nopath0".  It's a case of "explicit is better than implicit" without a clear reason, to me, that the status quo is worth the exception anymore in the face of the alternative.

My only concern would be backwards compatibility.  How much do scripts out there rely on the implicit sys.path[0] initialization that aren't already broken by the removal of implicit relative imports?  I simply don't know.

However, I do know that having the -p flag that Nick has recommended would be awesome.
History
Date User Action Args
2011-11-25 08:53:01eric.snowsetrecipients: + eric.snow, ncoghlan
2011-11-25 08:53:01eric.snowsetmessageid: <1322211181.82.0.909365539545.issue13475@psf.upfronthosting.co.za>
2011-11-25 08:53:01eric.snowlinkissue13475 messages
2011-11-25 08:52:59eric.snowcreate