codehack.py 2.37 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3 4 5 6 7 8 9
# A subroutine for extracting a function name from a code object
# (with cache)

import sys
from stat import *
import string
import os
import linecache

10 11 12
# XXX The functions getcodename() and getfuncname() are now obsolete
# XXX as code and function objects now have a name attribute --
# XXX co.co_name and f.func_name.
13 14
# XXX getlineno() is now also obsolete because of the new attribute
# XXX of code objects, co.co_firstlineno.
15

Guido van Rossum's avatar
Guido van Rossum committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
# Extract the function or class name from a code object.
# This is a bit of a hack, since a code object doesn't contain
# the name directly.  So what do we do:
# - get the filename (which *is* in the code object)
# - look in the code string to find the first SET_LINENO instruction
#   (this must be the first instruction)
# - get the line from the file
# - if the line starts with 'class' or 'def' (after possible whitespace),
#   extract the following identifier
#
# This breaks apart when the function was read from <stdin>
# or constructed by exec(), when the file is not accessible,
# and also when the file has been modified or when a line is
# continued with a backslash before the function or class name.
#
# Because this is a pretty expensive hack, a cache is kept.

SET_LINENO = 127 # The opcode (see "opcode.h" in the Python source)
identchars = string.letters + string.digits + '_' # Identifier characters

_namecache = {} # The cache

def getcodename(co):
39 40 41 42
	try:
		return co.co_name
	except AttributeError:
		pass
Guido van Rossum's avatar
Guido van Rossum committed
43 44 45 46 47 48 49 50
	key = `co` # arbitrary but uniquely identifying string
	if _namecache.has_key(key): return _namecache[key]
	filename = co.co_filename
	code = co.co_code
	name = ''
	if ord(code[0]) == SET_LINENO:
		lineno = ord(code[1]) | ord(code[2]) << 8
		line = linecache.getline(filename, lineno)
51
		words = line.split()
Guido van Rossum's avatar
Guido van Rossum committed
52 53 54 55 56 57 58 59 60 61 62 63
		if len(words) >= 2 and words[0] in ('def', 'class'):
			name = words[1]
			for i in range(len(name)):
				if name[i] not in identchars:
					name = name[:i]
					break
	_namecache[key] = name
	return name

# Use the above routine to find a function's name.

def getfuncname(func):
64 65 66 67
	try:
		return func.func_name
	except AttributeError:
		pass
Guido van Rossum's avatar
Guido van Rossum committed
68
	return getcodename(func.func_code)
69 70 71 72

# A part of the above code to extract just the line number from a code object.

def getlineno(co):
73 74 75 76
	try:
		return co.co_firstlineno
	except AttributeError:
		pass
77 78 79 80 81
	code = co.co_code
	if ord(code[0]) == SET_LINENO:
		return ord(code[1]) | ord(code[2]) << 8
	else:
		return -1