diff --git a/debug.py b/debug.py index ceee9e4f..29dc2505 100644 --- a/debug.py +++ b/debug.py @@ -1,7 +1,12 @@ +import inspect def dbg(*args): if debug_function: - debug_function(*args) + frm = inspect.stack()[1] + mod = inspect.getmodule(frm[0]) + if not (mod.__name__ in ignored_modules): + debug_function(*args) debug_function = None +ignored_modules = [] diff --git a/evaluate.py b/evaluate.py index b82e2a84..b55f3286 100644 --- a/evaluate.py +++ b/evaluate.py @@ -1,6 +1,8 @@ -import parsing import itertools + +import parsing import modules +import debug class Exec(object): @@ -129,6 +131,22 @@ def get_scopes_for_name(scope, name, search_global=False, search_func=None): res_new.append(r) return res_new + def filter_name(scopes): + # the name is already given in the parent function + result = [] + for scope in scopes: + if isinstance(scope, parsing.Import): + try: + i = follow_import(scope).get_defined_names() + except modules.ModuleNotFound: + debug.dbg('StarImport not found: ' + str(scope)) + else: + result += filter_name(i) + else: + if [name] == list(scope.names): + result.append(scope.parent) + return result + if search_func: names = search_func() elif search_global: @@ -136,8 +154,9 @@ def get_scopes_for_name(scope, name, search_global=False, search_func=None): else: names = scope.get_set_vars() - result = [c.parent for c in names if [name] == list(c.names)] - return remove_statements(result) + # TODO here are the star imports handled, we need to get the names here. + # This means things like from pylab import * + return remove_statements(filter_name(names)) def follow_statement(stmt, scope=None): @@ -233,13 +252,13 @@ def follow_path(path, input): for s in stmts: result += add_result(current, s) #except AttributeError: - # dbg('cannot execute:', input) + # debug.dbg('cannot execute:', input) elif isinstance(input, parsing.Import): print 'dini mueter, steile griech!' try: - modules.follow_module(input) + result.append(follow_import(input)) except modules.ModuleNotFound: - dbg('Module not found: ' + str(input)) + debug.dbg('Module not found: ' + str(input)) else: # TODO check default class methods and return them also result = get_scopes_for_name(input, current) @@ -251,9 +270,23 @@ def follow_path(path, input): return follow_paths(path, add_result(cur, input)) -def dbg(*args): - if debug_function: - debug_function(*args) +def follow_import(_import): + """ + follows a module name and returns the parser. + :param _import: The import statement. + :type _import: parsing.Import + """ + # set path together + ns_list = [] + if _import.from_ns: + ns_list += _import.from_ns.names + if _import.namespace: + ns_list += _import.namespace.names + scope, rest = modules.find_module(ns_list) + if rest: + scope = follow_path(rest.__iter__(), scope) + + debug.dbg('after import', scope, rest) + return scope -debug_function = None diff --git a/modules.py b/modules.py index 968ce0d7..11873fc2 100644 --- a/modules.py +++ b/modules.py @@ -16,12 +16,11 @@ class ModuleNotFound(Exception): class File(object): """ Manages all files, that are parsed and caches them. - If the source is not given, it is loaded by load_module. :param source: The source code of the file. :param module_name: The module name of the file. """ - def __init__(self, module_name, source=None): + def __init__(self, module_name, source): self.source = source self.module_name = module_name self._line_cache = None @@ -37,13 +36,6 @@ class File(object): return self.load_module() def load_module(self): - if not self.source: - if i[0]: # is the file pointer - self.source = open(i[0]).read() - print self.source, 'yesssa' - else: - self.source = '' - print 'shizzel' self._parser = parsing.PyFuzzyParser(self.source) return self._parser @@ -56,45 +48,62 @@ class File(object): else: return None +class BuiltinModule: + def __init__(self, name): + self.name = name + self.content = {} + exec 'import %s as module' % name in self.content + self.module = self.content['module'] -def follow_module(_import): + @property + def docstr(self): + # TODO get the help string, not just the docstr + return self.module.__doc__ + + def get_defined_names(self): + return dir(self.module) + +def find_module(point_path): """ - follows a module name and returns the parser. - :param name: A name from the parser. - :type name: parsing.Name + Find a module with a path (of the module, like usb.backend.libusb10). + + :param point_path: A name from the parser. + :return: The rest of the path, and the module top scope. """ def follow_str(ns, string): - print ns, string + debug.dbg('follow_module', ns, string) if ns: path = ns[1] else: + # TODO modules can be system modules, without '.' in path path = module_find_path debug.dbg('search_module', string, path) - i = imp.find_module(string, path) + try: + i = imp.find_module(string, path) + except ImportError: + # find builtins (ommit path): + i = imp.find_module(string) + if i[0]: + # if the import has a file descriptor, it cannot be a builtin. + raise return i - # set path together - ns_list = [] - if _import.from_ns: - ns_list += _import.from_ns.names - if _import.namespace: - ns_list += _import.namespace.names - # now execute those paths current_namespace = None - rest = None - for i, s in enumerate(ns_list): + rest = [] + for i, s in enumerate(point_path): try: current_namespace = follow_str(current_namespace, s) except ImportError: if current_namespace: - rest = ns_list[i:] + rest = point_path[i:] else: raise ModuleNotFound( 'The module you searched has not been found') - print 'yay', current_namespace - f = File(current_namespace[2], current_namespace[0].read()) - out = f.parser.top.get_names() - print out - return parser + if current_namespace[0]: + f = File(current_namespace[2], current_namespace[0].read()) + scope = f.parser.top + else: + scope = BuiltinModule(current_namespace[1]) + return scope, rest diff --git a/parsing.py b/parsing.py index cf1aff85..e162bb1c 100644 --- a/parsing.py +++ b/parsing.py @@ -814,7 +814,7 @@ class PyFuzzyParser(object): token_type, tok, indent = self.next() start_line = self.line_nr if token_type != tokenize.NAME and tok != '*': - return ([], tok) + return ([], token_type, tok, indent, start_line) else: token_type, tok, indent = pre_used_token start_line = self.line_nr @@ -1100,7 +1100,7 @@ class PyFuzzyParser(object): self.gen = tokenize.generate_tokens(buf.readline) self.currentscope = self.scope - extended_flow = ['else', 'except', 'finally'] + extended_flow = ['else', 'elif', 'except', 'finally'] statement_toks = ['{', '[', '(', '`'] decorators = [] diff --git a/test.py b/test.py index 0db87136..a700e6cf 100644 --- a/test.py +++ b/test.py @@ -130,7 +130,7 @@ import time class c1(): c2,c5 = c1(), c1().c3() def c3(self): - from os import F_OK as c4 + from parsing import Scope as c4 c5 = c4 c5 = 1 return c5+1+'asdf'