# Python 3 minor irritation

Benjamin Kaplan benjamin.kaplan at case.edu
Thu Feb 4 05:41:00 CET 2010

On Wed, Feb 3, 2010 at 11:18 PM, Alf P. Steinbach <alfps at start.no> wrote:
> * Benjamin Kaplan:
>>
>> On Wed, Feb 3, 2010 at 9:56 PM, Alf P. Steinbach <alfps at start.no> wrote:
>>>
>>> * David Monaghan:
>>>>
>>>> I have a small program which reads files from the directory in which it
>>>> resides. It's written in Python 3 and when run through IDLE or PythonWin
>>>> works fine. If I double-click the file, it works fine in Python 2.6, but
>>>> in
>>>> 3 it fails because it looks for the files to load in the Python31
>>>> folder,
>>>> not the one the script is in.
>>>>
>>>> It's not a big deal, but browsing around I haven't found why the
>>>> behaviour
>>>> has been changed or any comment about it (That might be my poor search
>>>> technique, I suppose).
>>>>
>>>> The program fails at:
>>>>
>>>>   try:
>>>>       tutdoc = minidom.parse(".//Myfile.xml")
>>>>   except IOError:
>>>>       <snip>
>>>
>>> The "//" is wrong, but should not cause the behavior that you describe.
>>>
>>> Try to post a complete smallest possible program that exhibits the
>>> problem.
>>>
>>> Possibly, in creating that example you'll also find what's cause the
>>> problem. :-)
>>>
>>>
>>> Cheers & hth.,
>>>
>>> - Alf
>>
>> That is the smallest example the exhibits the problem.
>
> No, it doesn't seem to exhibit the problem at all. :-)
>
>
>> It's not an
>> issue with the Python code, it's an issue with how Windows is running
>> it. I don't know enough about the way Windows Explorer runs files, but
>> it seems to be doing the equivalent of
>> cd C:\Python31
>> python31.exe C:\full\path\to\script\foo.py
>>
>> cd C:\full\path\path\to\script
>> C:\Python31\python.exe foo.py
>> which is David expected. This throws off the relative filepath.
>
> No, this is not what happens.
>
> What happens is that when you double-click the script, then __file__ is set
> to the absolute path instead of just the filename, at least on my machine
> (XP); whether the full path or just the filename is passed on the OS level
> depends, however, on the Windows version.
>
> The current directory is always (initially) correct, as the script's
> directory.
>

Read my first paragraph again- it has absolutely nothing to do with
Python. It has to do with how the Windows is running Python 3 on the
OP's computer. The OP's description said that it was looking for the
file .\\myfile.xml in C:\Python31 which means it translated '.', the
current working directory, to be C:\Python31 and not the directory the
script is in.

>
>> The easiest way to solve this permanently, by the way, is to not use
>> relative paths. All it takes is one script to call os.chdir and the
>> script breaks. You can use __file__ and the os.path module to figure
>> out exactly where you are in an OS-agnostic way.
>>
>> import os.path
>> #get the absolute path to the current script
>> abs_path = os.path.abspath(__file__)
>
> According to the docs: "On most platforms, this is equivalent to
> normpath(join(os.getcwd(), path))."
>

os.path.abspath will always work in this case (unless something
changes the current working directory before that statement runs)
because __file__ is given either as an absolute path or as relative to
the current working directory.

----- /Users/bkaplan/test/test.py
print(__file__)
import os.path
print(os.path.abspath(__file__))
------------------

$cd /users/bkaplan$ python3 test/test.py
python3 test/test.py
test/test.py
/Users/bkaplan/test/test.py

$cd /users/bkaplan/test$ python3 test.py
test.py
/Users/bkaplan/test/test.py

If abspath is given an absolute path, it won't touch it

Output from double clicking on the file:
/Users/bkaplan/test/test.py
/Users/bkaplan/test/test.py

> Therefore, if getcwd() is not the script's directory, as you hypothesize
> above, then most likely the result of this code is Not The Path You're
> Looking For.
>

Except that if the cwd is not the directory the script is running in,
__file__ should still point to it either through an absolute path
(highly likely since it's run through Windows Explorer) or some
(however convoluted) relative path.

> However, since the current directory is in fact OK, the above is one way to
> get a sort of canonical (a where-you-know-the-format) representation of
> __file__.
>
>
>>  # get the full path to the directory of the script
>> directory = os.path.dirname(abs_path)
>
> This is very much likely to yield the same result as calling os.getcwd();
> see above.
>

Not if there is more than one folder between __file__ and cwd. For
instance, if the script is in a package several directories down from
the main script.

>
>> #get the full path to your file
>> my_file = os.path.join(directory, "MyFile.xml")
>
>
> Cheers & hth.,
>
> - Alf
> --
> http://mail.python.org/mailman/listinfo/python-list
>