uwain12345
uwain12345

Reputation: 386

Cannot use __file__ when running startup file in IDLE's normal mode

I've written a little batch file (Windows 8.1) to start my script directly in IDLE:

START "" pythonw.exe "C:\Program Files (x86)\Python36-32\Lib\idlelib\idle.py" -r my_script.py

The script contains the line

my_dir = os.path.split(__file__)[0]

which produces a name error

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files (x86)\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "my_script.py", line 245, in out_file_dia
    my_dir = os.path.split(__file__)[0]
NameError: name '__file__' is not defined

If I open IDLE first and then start the script, it works fine. Why is

__file__

not defined in this situation?

Upvotes: 0

Views: 386

Answers (1)

Terry Jan Reedy
Terry Jan Reedy

Reputation: 19144

In interactive mode, the input 'file' is the stream of statements entered by the user, so __file__ is left unset. If there is a PYTHONSTARTUP file, __file__ is set to that filename while the file is run, then unset before the first >>> prompt. Currently, IDLE does not do this when running user code in a separate process, which is now the normal mode.

I opened https://bugs.python.org/issue32984 to fix this. I will try to remember to report here when it is.

When IDLE is started with -n, to use the old deprecated mode in which user code is executed in the IDLE GUI process, startup files and interactive input see __file__ set to an idlelib file. Both are wrong but will not be fixed.

EDIT: PR-5981, which works for me on Windows, modifies pyshell.execfile to begin as follows:

def execfile(self, filename, source=None):  # currently line 633
    "Execute an existing file"
    if source is None:
        with tokenize.open(filename) as fp:
            source = fp.read()
            if use_subprocess:
                source = (f"__file__ = r'''{os.path.abspath(filename)}'''\n"
                          + source + "\ndel __file__")

The last 3 lines are new. uwain12345, adding them should solve your problem. If not, I would like to know.

EDIT 2: tweek replacement code to allow for ' in startup file name.

Note: f strings are new in 3.6. For older Pythons, replace the source line with

                filename = os.path.abspath(filename)
                source = ("__file__ = r'''{}'''\n".format(filename)

Upvotes: 2

Related Questions