def _ast_mod_source_from_module_and_name(self, module, name): """ Retreive the AST and module source for a function given its module and name. If it fails to find the module or find the function within the module, set the load_error appropriately and return None. Otherwise, return the FuncDef ast for the function. Additionally, return the module source for use with other parsers. """ # Find the source code for the specified module. try: loader = _pkgutil.get_loader(module) except: # A variety of exceptions can be thrown from getting the loader, # mostly dealing with a failure to parse an __init__.py file self.load_error = "failed to find module '%s'" % self.module return None, None if loader is None: self.load_error = "failed to find module '%s'" % self.module return None, None # fixme: Can this fail if the above succeeded? module_source = loader.get_source() # Convert it to an ast, and find all function asts defined in it. try: module_ast = compiler.parse(module_source) except: # This catches parse errors in the python source self.load_error = "failed to parse module '%s'" % self.module return None, None # fixme: find_local_defs is a bit primitive. If we have problems, # with finding the wrong function, this is the place to look. funcs = parse_tools.find_local_defs(module_ast) ast = funcs.get(name, None) if ast is None: # fixme much better error handling here. self.load_error = "failed to find '%s' in module '%s'" % \ (self.name, self.module) return ast, module_source
def _code_changed(self): """ Whenever the code changes, try and update the input and output arguments. fixme: We only handle one function definition in the code. Fix this to where we allow local functions, and we are defined by the first function in the file. """ # If we fail to parse the ast, our current behavior is to reset # all our values to empty and set our invalid flag. try: ast = compiler.parse(self.code) except: # If the code failed to load, invalidate all traits, # set the load error based on the exception that happened, # and set ast to None so that we don't do any further # processing. ast = None if ast is not None: functions = find_local_defs(ast) if functions.items(): # Use the first function we find as the one used for this # local function. # fixme: Should we raise an error if we find more? # fixme: find_local_defs will loose a function def if there are # two versions with same name. name, function_ast = functions.items()[0] self._initialize_from_ast(function_ast) self.load_error = "" else: # There weren't any functions found to initialize from. self._initialize_as_invalid() self.load_error = "No function definition found." else: self._initialize_as_invalid() # fixme: For now we just report the type of error. This # should be improved. self.load_error = "%s" % exception_info()[0]