On Oct 27, 3:14 am, Andrew West <[EMAIL PROTECTED]> wrote: > Probably a bit of weird question. I realise decorators shouldn't be > executed until the function they are defined with are called, but is > there anyway for me to find all the decorates declared in a file when > I import it? Or perhaps anyway to find the decorators by loading the > file by other methods (with out simply parsing it by hand).
There is no need for having *parser Angst* in Python. Once you understand the syntactical structure of the language it's easy to move on. I show you how to deal with it using EasyExtend for grepping parse trees ( which is much easier than using regexps for that purpose ). Alternatively you can use the compiler package. It hides some low level stuff being present in EE on this level. You need to decide how you want to reduce mental overhead and achieve simplicity that "fits your brain". EasyExtend is available at www.fiber-space.de Here is a small tutorial: # purpose -- seeking for decorators and decorated functions in Python 2.5 stdlibs contextlib.py import inspect import parser import symbol import token # just import contextlib, keep source and create a parse tree import contextlib src = inspect.getsource(contextlib) # keep source cst = parser.suite(src).tolist() # create concrete syntax tree as a nested list # so far its all standard lib stuff... # ... now something new: from EasyExtend.csttools import find_node, find_all functions = find_all(cst, symbol.funcdef) # You need to know how these nodes are structured to get more information out of them # This can be looked up in EasyExtend/Grammar which contains a copy of Pythons Grammar or # in the same file in Pythons source distribution. Here are the relevant rules: # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE # decorators: decorator+ # funcdef: [decorators] 'def' NAME parameters ':' suite # We see immediately that it's not all that simple. Decorators can be methods and the first name # in dotted-name can be the name of an object. For demonstration purposes we simplify our # assumptions and suppose to have plain function decorators func_info = {} for f in functions: decorator_info = set() # store decorator information here decorators = find_node(f, symbol.decorators) # we do *not* want all decorators # since there might be those related to # a closure that is handled separately if decorators: decos = find_all(decorators, symbol.decorator) for deco in decos: # token.NAME has structure [1, 'name', line_no] deco_name = find_node(deco, token.NAME)[1] args = find_node(deco, symbol.arglist) # ... we analyze args later decorator_info.add((deco_name, args)) f_names = find_all(f, token.NAME, level = 1) # set level information otherwise you # get all names defined anywhere in # funcdef func_name = f_names[1][1] # the first name is 'def', the second one the func_name func_info[func_name] = decorator_info # Note: you can move from syntax tree representation straightforward back to a textual # representation. This requires not much work but the following import is nevertheless # conceptual overhead I do not try to explain in detail here: from EasyExtend.fibers.zero.fiber import unparse # zero represents *Python* in the larger # context of EasyExtend applications # unparse transforms a cst of a particular # grammar back to source code for func_name, deco_info in func_info.items(): for (deco_name, deco_args) in deco_info: print func_name, deco_name, (unparse(deco_args) if deco_args else "()") # I get the rather unspectacular result # nested contextmanager () # You might verify this manually... -- http://mail.python.org/mailman/listinfo/python-list