PEP: 235 Title: Import on Case-Insensitive Platforms Version: $Revision$
Last-Modified: $Date$ Author: Tim Peters <tim.peters@gmail.com> Status:
Final Type: Standards Track Content-Type: text/x-rst 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:
