views:

113

answers:

2

Hello, everyone

I am using a piece of self-modifying code for a college project.

Here it is:

import datetime
import inspect
import re
import sys

def main():
    # print the time it is last run
    lastrun = 'Mon Jun  8 16:31:27 2009'

    print "This program was last run at ",
    print lastrun

    # read in the source code of itself
    srcfile = inspect.getsourcefile(sys.modules[__name__])
    f = open(srcfile, 'r')
    src = f.read()
    f.close()

    # modify the embedded timestamp
    timestamp = datetime.datetime.ctime(datetime.datetime.now())
    match = re.search("lastrun = '(.*)'", src)
    if match:
        src = src[:match.start(1)] + timestamp + src[match.end(1):]

    # write the source code back
    f = open(srcfile, 'w')
    f.write(src)
    f.close()

if __name__=='__main__':
    main()

Unfortunately, it doesn't work. Error returned:

# This is the script's output
This program is last run at  Mon Jun  8 16:31:27 2009
# This is the error message
Traceback (most recent call last):
  File "C:\Users\Rui Gomes\Desktop\teste.py", line 30, in <module>
    main()
  File "C:\Users\Rui Gomes\Desktop\teste.py", line 13, in main
    srcfile = inspect.getsourcefile(sys.modules[__name__])
  File "C:\Python31\lib\inspect.py", line 439, in getsourcefile
    filename = getfile(object)
  File "C:\Python31\lib\inspect.py", line 401, in getfile
    raise TypeError('{!r} is a built-in module'.format(object))
TypeError: <module '__main__' (built-in)> is a built-in module

I'd be thankful for any solutions.

+4  A: 

It runs perfectly when run outside of IDLE -- so therefore the problem is not in your code alone, but in the environment where you are executing it. When you run the erroring portion of your code in IDLE you get this output:

>>> import inspect
>>> sys.modules[__name__]
<module '__main__' from 'C:\Python26\Lib\idlelib\idle.pyw'>
>>> inspect.getsourcefile(sys.modules[__name__])
'C:\\Python26\\Lib\\idlelib\\idle.pyw'

When you run this in IDLE

# read in the source code of itself
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'r')
src = f.read()
f.close()

you are actually trying to modify 'C:\\Python26\\Lib\\idlelib\\idle.pyw' ... which IDLE will not let you do.

The long and the short of it seems to be that what you have written does work: but it cannot be run in IDLE.

Sean Vieira
The problem is not related with the openfile part because the exception is triggered in inspect.getsourcefile(sys.modules[__name__])
joaquin
Thanks, fixed it.
Francisco P.
+3  A: 

You could use the __file__ global attribute to get the current module's source path.

From the 2.6 docs:

__file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. The __file__ attribute is not present for C modules that are statically linked into the interpreter; for extension modules loaded dynamically from a shared library, it is the pathname of the shared library file.

EDIT:

I made the assumption that inspect.getsourcefile() would always throw TypeError when inspecting the __main__ module. That's only the case when run from an interactive interpreter. I stand corrected. Derp.

Jeremy Brown