python-peps / pep-0235.txt

PEP: 235
Title: Import on Case-Insensitive Platforms
Version: $Revision$
Last-Modified: $Date$
Author: Tim Peters <tim@zope.com>
Status: Final
Type: Standards Track
Created:
Python-Version: 2.1
Post-History: 16 February 2001


Note

    This is essentially a retroactive PEP: the issue came up too late
    in the 2.1 release process to solicit wide opinion before deciding
    what to do, and can't be put off until 2.2 without also delaying
    the Cygwin and MacOS X ports.


Motivation

    File systems vary across platforms in whether or not they preserve
    the case of filenames, and in whether or not the platform C
    library file-opening functions do or don't insist on
    case-sensitive matches:

                      case-preserving     case-destroying
                     +-------------------+------------------+
    case-sensitive   | most Unix flavors | brrrrrrrrrr      |
                     +-------------------+------------------+
    case-insensitive | Windows           | some unfortunate |
                     | MacOSX HFS+       | network schemes  |
                     | Cygwin            |                  |
                     |                   | OpenVMS          |
                     +-------------------+------------------+

    In the upper left box, if you create "fiLe" it's stored as "fiLe",
    and only open("fiLe") will open it (open("file") will not, nor
    will the 14 other variations on that theme).

    In the lower right box, if you create "fiLe", there's no telling
    what it's stored as -- but most likely as "FILE" -- and any of the
    16 obvious variations on open("FilE") will open it.

    The lower left box is a mix: creating "fiLe" stores "fiLe" in the
    platform directory, but you don't have to match case when opening
    it; any of the 16 obvious variations on open("FILe") work.

    NONE OF THAT IS CHANGING!  Python will continue to follow platform
    conventions w.r.t. whether case is preserved when creating a file,
    and w.r.t. whether open() requires a case-sensitive match.  In
    practice, you should always code as if matches were
    case-sensitive, else your program won't be portable.

    What's proposed is to change the semantics of Python "import"
    statements, and there *only* in the lower left box.


Current Lower-Left Semantics

    Support for MacOSX HFS+, and for Cygwin, is new in 2.1, so nothing
    is changing there.  What's changing is Windows behavior.  Here are
    the current rules for import on Windows:

    1. Despite that the filesystem is case-insensitive, Python insists
       on a case-sensitive match.  But not in the way the upper left
       box works: if you have two files, FiLe.py and file.py on
       sys.path, and do

           import file

       then if Python finds FiLe.py first, it raises a NameError.  It
       does *not* go on to find file.py; indeed, it's impossible to
       import any but the first case-insensitive match on sys.path,
       and then only if case matches exactly in the first
       case-insensitive match.

    2. An ugly exception: if the first case-insensitive match on
       sys.path is for a file whose name is entirely in upper case
       (FILE.PY or FILE.PYC or FILE.PYO), then the import silently
       grabs that, no matter what mixture of case was used in the
       import statement.  This is apparently to cater to miserable old
       filesystems that really fit in the lower right box.  But this
       exception is unique to Windows, for reasons that may or may not
       exist.

    3. And another exception: if the environment variable PYTHONCASEOK
       exists, Python silently grabs the first case-insensitive match
       of any kind.

    So these Windows rules are pretty complicated, and neither match
    the Unix rules nor provide semantics natural for the native
    filesystem.  That makes them hard to explain to Unix *or* Windows
    users.  Nevertheless, they've worked fine for years, and in
    isolation there's no compelling reason to change them.

    However, that was before the MacOSX HFS+ and Cygwin ports arrived.
    They also have case-preserving case-insensitive filesystems, but
    the people doing the ports despised the Windows rules.  Indeed, a
    patch to make HFS+ act like Unix for imports got past a reviewer
    and into the code base, which incidentally made Cygwin also act
    like Unix (but this met the unbounded approval of the Cygwin
    folks, so they sure didn't complain -- they had patches of their
    own pending to do this, but the reviewer for those balked).

    At a higher level, we want to keep Python consistent, by following
    the same rules on *all* platforms with case-preserving
    case-insensitive filesystems.


Proposed Semantics

    The proposed new semantics for the lower left box:

    A. If the PYTHONCASEOK environment variable exists, same as
       before: silently accept the first case-insensitive match of any
       kind; raise ImportError if none found.

    B. Else search sys.path for the first case-sensitive match; raise
       ImportError if none found.

    #B is the same rule as is used on Unix, so this will improve cross-
    platform portability.  That's good.  #B is also the rule the Mac
    and Cygwin folks want (and wanted enough to implement themselves,
    multiple times, which is a powerful argument in PythonLand).  It
    can't cause any existing non-exceptional Windows import to fail,
    because any existing non-exceptional Windows import finds a
    case-sensitive match first in the path -- and it still will.  An
    exceptional Windows import currently blows up with a NameError or
    ImportError, in which latter case it still will, or in which
    former case will continue searching, and either succeed or blow up
    with an ImportError.

    #A is needed to cater to case-destroying filesystems mounted on Windows,
    and *may* also be used by people so enamored of "natural" Windows
    behavior that they're willing to set an environment variable to
    get it.  I don't intend to implement #A for Unix too, but that's
    just because I'm not clear on how I *could* do so efficiently (I'm
    not going to slow imports under Unix just for theoretical purity).

    The potential damage is here: #2 (matching on ALLCAPS.PY) is
    proposed to be dropped.  Case-destroying filesystems are a
    vanishing breed, and support for them is ugly.  We're already
    supporting (and will continue to support) PYTHONCASEOK for their
    benefit, but they don't deserve multiple hacks in 2001.



Local Variables:
mode: indented-text
indent-tabs-mode: nil
End:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.