3

Some code of mine sprung a bug seemingly out of nowhere. When I tracked it down, I found that evaluating inspect.getmodule with the same (identical) argument before and after executing os.chdir gives different results.

(FWIW, I'm running Python 2.7.3, under OS X.)

I find this behavior so puzzling and bewildering that I don't know how best to fix the bug. (In other words, with understanding the reason for the behavior, anything solution I can think of is only a band-aid.)

The test script below illustrates the behavior (although, of course, the real-life bug occurred in a far more realistic and complex context):

import inspect
import os

def prn(line, mod):
    print ('getmodule called at line %2d; returned module: %-8s (id: %d)' %
           (line - 1, getattr(mod, '__name__', mod), id(mod)))

fr = inspect.currentframe()

mod = inspect.getmodule(fr) # line 10
prn(fr.f_lineno, mod)

mod = inspect.getmodule(fr) # line 13
prn(fr.f_lineno, mod)

os.chdir('subdir')

mod = inspect.getmodule(fr) # line 18
prn(fr.f_lineno, mod)

(NOTE: running this code requires that there be a subdirectory called "subdir" immediately under the current directory.)

Its output is:

getmodule called at line 10; returned module: __main__ (id: 4297636784)
getmodule called at line 13; returned module: __main__ (id: 4297636784)
getmodule called at line 18; returned module: None     (id: 4296513024)

Note that, although all three calls to getmodule have the same frame object as argument, the result of the last one differs from the results produced the first two. (The results from the first two calls are identical, as one would expect.)

The only difference between the first two calls and the third one is that the latter takes place after running os.chdir.

Any insight on what's going on would be appreciated.

kjo
  • 33,683
  • 52
  • 148
  • 265

2 Answers2

0

I tried running the code on Idle Python 2.7.2 and 2.7.3 on Windows 7 X64, but, I am not able to reproduce this. All I get is:-

getmodule called at line 12; returned module: main (id: 31281464)
getmodule called at line 15; returned module: main (id: 31281464)
getmodule called at line 20; returned module: main (id: 31281464)

But, I think the problem is the implementation. As is evident in the Python documentation: http://docs.python.org/library/inspect.html#inspect.getmodule, Try to guess which module an object was defined in.

I think (this is just an assumption as I can't reproduce your observations on my system) before you have changed the current directory, as you are in the parent directory, the module is shown as main, hence you receive the id: 4297636784. But, after you changed the current directory, the module can not be referenced from the new directory, hence the new id: 4296513024 is returned to you with None as the module because the main module can't be referenced from the new directory.

GodMan
  • 2,561
  • 2
  • 24
  • 40
0

I think the issue here is that the module you're inspecting is also the __main__ module. If you put your example code into another module and import that into your main one, it works fine. The fact that you're changing working directory after grabbing the frame isn't doing you any favours either.

If you absolutely need for a module to also be the application, you can manually pass the path into inspect.getmodule:

import os
import inspect

__filepath__ = os.path.join(os.getcwd(), __file__)

frame = inspect.currentframe()
os.chdir('subdir')
print inspect.getmodule(frame, _filename=__filepath__).__name__

However, are you absolutely sure you need to change working directory like you're doing? In the 8+ years I've been coding Python, I don't recall ever using it in real world code.

Matthew Trevor
  • 14,354
  • 6
  • 37
  • 50