Monday, April 26, 2010

Python Introspection/Reflection Utility Class

So the code below is for a python module 'mir.py', and contains a class 'Mir' and a rather thin main method 'run()' which demos the class.


class Mir:
"""mirror introspection/reflection class"""

meth_lookup_token_len = len('<function')
meth_type_lookup = {
'<bound me' : 'instance',
'<function' : 'static',
'<method-wr' : 'wrapper',
'<built-in ' : 'built-in'
}

def __init__(self):
"""docstring for initializer"""
pass

@staticmethod
def ins(target,show_magic_meths=False):

lines = []

"""provide basic information on the target"""

# column widthss
c1 = 20
c2 = 20
c3 = 40

field_names = []
method_names = []
mangled_field_names = []

dir_list = dir(target)

for ob in dir_list:

if (callable(getattr(target, ob))):
method_names.append(ob)
else:
field_names.append(ob)

# FIELDS --------------------------------------

# double leading and trailing underscore
magic_fields = []
# starts and ends with alphabetic
normal_fields = []

# double leading underscore # mangledFields = []
# single leading underscore # privateFields = []

for field_name in field_names:

a = getattr(target, field_name)
l = len(field_name)

# magic fields
if (field_name[0:2] == '__'):
if (field_name[l - 2 : l] == '__'):
magic_fields.append(field_name)
else:
mangled_field_names.append(field_names)
else:
normal_fields.append(field_name)

if '__doc__' in magic_fields:
docstring = getattr(target, '__doc__')
else:
docstring = 'no doc string'

if '__module__' in magic_fields:
moduleName = getattr(target, '__module__')
else:
moduleName = 'no module'

# METHODS

# class methods
# instance methods
# - constructor
# - vanilla

static_methods = []
instance_methods = []

magic_methods = []

meth_info = []

for method_name in method_names:

# DETERMINE METHOD TYPE = INSTANCE, STATIC

a = getattr(target, method_name)
try:
s = (str(a))
token = s[0:Mir.meth_lookup_token_len+1]
meth_type = Mir.meth_type_lookup[token]
except:
meth_type = s[0:c2]
else:
pass

# GET METHOD DOC-STRING

meth_docstring = getattr(a, '__doc__')

if (meth_docstring == None):
meth_docstring = ''
else:
meth_docstring = meth_docstring.replace('\n', ' | ')

if (meth_type == 'static'):
static_methods.append((method_name, meth_docstring))
elif (meth_type == 'instance'):
instance_methods.append((method_name, meth_docstring))
else:
pass

L = len(method_name)
prefix = (method_name[0:2] == '__')
suffix = (method_name[L-2:L] == '__')
if (prefix and suffix):
magic_methods.append(method_name)

meth_info.append((method_name, meth_type, meth_docstring))

lines.append('----------------------------------------------------------------------')
lines.append('target = ' + str(target))
lines.append('target type = ' + str(type(target)))
lines.append('source module: %s' % moduleName)
lines.append('----------------------------------------------------------------------')
lines.append('docstring: %s' % docstring)
lines.append('')
lines.append('----------------------------------------------------------------------')
lines.append('FIELDS')
lines.append('---------------')
# static
# class
# instance

for field_name in normal_fields:
a = getattr(target, field_name)
lines.append(field_name.ljust(20) + str(a).ljust(30))

if (show_magic_meths):
lines.append('----------------------------------------------------------------------')
lines.append('METHODS - MAGIC')
lines.append('---------------')
for (meth_name, meth_type, methDoc) in meth_info:
if (meth_name in magic_methods):
lines.append(meth_name.ljust(c1) + meth_type.ljust(c2) + methDoc.ljust(c3))

lines.append('----------------------------------------------------------------------')
lines.append('METHODS - NON-MAGIC')
lines.append('---------------')
for (meth_name, meth_type, methDoc) in meth_info:
if (meth_name not in magic_methods):
lines.append(meth_name.ljust(c1) + meth_type.ljust(c2) + methDoc.ljust(c3))

return lines

@staticmethod
def inspect(target):

lines = Mir.ins(target)

for line in lines:
print(line)

@staticmethod
def ins2f(target, fname):

file = open(fname, 'w')
for line in Mir.ins(target):
file.write(line + '\n')
file.close()


# #########################################################

def run():

lis = []
Mir.inspect(lis)

if __name__ == '__main__':

No comments:

Post a Comment

comment: