def make_fakestatement(self, lhs, rhs, call=False): """ Make a fake statement object that represents ``lhs = rhs``. :type call: bool :arg call: When `call` is true, make a fake statement that represents ``lhs = rhs()``. :rtype: :class:`parsing_representation.Statement` """ submodule = self.scope._sub_module lhsname = pr.Name(module=submodule, names=[(lhs, (0, 0))], start_pos=(0, 0), end_pos=(None, None)) rhsname = pr.Name(module=submodule, names=[(rhs, (0, 0))], start_pos=(0, 0), end_pos=(None, None)) token_list = [lhsname, (tokenize.OP, '=', (0, 0)), rhsname] if call: token_list.extend([ (tokenize.OP, '(', (0, 0)), (tokenize.OP, ')', (0, 0)), ]) return pr.Statement(module=submodule, set_vars=[lhsname], used_vars=[rhsname], token_list=token_list, start_pos=(0, 0), end_pos=(None, None))
def make_fakeimport(self, module, variable=None, alias=None): """ Make a fake import object. The following statements are created depending on what parameters are given: - only `module`: ``import <module>`` - `module` and `variable`: ``from <module> import <variable>`` - all: ``from <module> import <variable> as <alias>`` :type module: str :arg module: ``<module>`` part in ``from <module> import ...`` :type variable: str :arg variable: ``<variable>`` part in ``from ... import <variable>`` :type alias: str :arg alias: ``<alias>`` part in ``... import ... as <alias>``. :rtype: :class:`parsing_representation.Import` """ submodule = self.scope._sub_module if variable: varname = pr.Name(module=submodule, names=[(variable, (-1, 0))], start_pos=(-1, 0), end_pos=(None, None)) else: varname = None modname = pr.Name(module=submodule, names=[(module, (-1, 0))], start_pos=(-1, 0), end_pos=(None, None)) if alias: aliasname = pr.Name(module=submodule, names=[(alias, (-1, 0))], start_pos=(-1, 0), end_pos=(None, None)) else: aliasname = None if varname: fakeimport = pr.Import(module=submodule, namespace=varname, from_ns=modname, alias=aliasname, start_pos=(-1, 0), end_pos=(None, None)) else: fakeimport = pr.Import(module=submodule, namespace=modname, alias=aliasname, start_pos=(-1, 0), end_pos=(None, None)) return fakeimport
def _parse_class(self): """ The parser for a text class. Process the tokens, which follow a class definition. :return: Return a Scope representation of the tokens. :rtype: Class """ first_pos = self.start_pos token_type, cname = self.next() if token_type != tokenize.NAME: debug.warning( "class: syntax err, token is not a name@%s (%s: %s)" % (self.start_pos[0], tokenize.tok_name[token_type], cname)) return None cname = pr.Name(self.module, [(cname, self.start_pos)], self.start_pos, self.end_pos) super = [] token_type, _next = self.next() if _next == '(': super = self._parse_parentheses() token_type, _next = self.next() if _next != ':': debug.warning("class syntax: %s@%s" % (cname, self.start_pos[0])) return None # because of 2 line class initializations scope = pr.Class(self.module, cname, super, first_pos) if self.user_scope and scope != self.user_scope \ and self.user_position > first_pos: self.user_scope = scope return scope
def keyword_names(*args, **kwargs): kwds = [] for k in keywords(*args, **kwargs): start = k.start_pos end = start[0], start[1] + len(k.name) kwds.append(pr.Name(k.parent, [(k.name, start)], start, end, k)) return kwds
def get_defined_names(self, on_import_stmt=False): names = [] for scope in self.follow(): if scope is ImportPath.GlobalNamespace: if self._is_relative_import() == 0: names += self._get_module_names() if self.file_path is not None: path = os.path.abspath(self.file_path) for i in range(self.import_stmt.relative_count - 1): path = os.path.dirname(path) names += self._get_module_names([path]) if self._is_relative_import(): rel_path = self._get_relative_path() + '/__init__.py' with common.ignored(IOError): m = modules.Module(rel_path) names += m.parser.module.get_defined_names() else: if on_import_stmt and isinstance(scope, pr.Module) \ and scope.path.endswith('__init__.py'): pkg_path = os.path.dirname(scope.path) paths = self._namespace_packages(pkg_path, self.import_path) names += self._get_module_names([pkg_path] + paths) if self.is_just_from: # In the case of an import like `from x.` we don't need to # add all the variables. if [ 'os' ] == self.import_path and not self._is_relative_import(): # os.path is a hardcoded exception, because it's a # ``sys.modules`` modification. p = (0, 0) names.append( pr.Name(self.GlobalNamespace, [('path', p)], p, p, self.import_stmt)) continue for s, scope_names in evaluate.get_names_of_scope( scope, include_builtin=False): for n in scope_names: if self.import_stmt.from_ns is None \ or self.is_partial_import: # from_ns must be defined to access module # values plus a partial import means that there # is something after the import, which # automatically implies that there must not be # any non-module scope. continue names.append(n) return names
def get_module_names(self, search_path=None): """ Get the names of all modules in the search_path. This means file names and not names defined in the files. """ if not search_path: search_path = self.sys_path_with_modifications() names = [] for module_loader, name, is_pkg in pkgutil.iter_modules(search_path): inf_pos = (float('inf'), float('inf')) names.append( pr.Name(self.GlobalNamespace, [(name, inf_pos)], inf_pos, inf_pos, self.import_stmt)) return names
def get_nested_import(self, parent): """ See documentation of `self.is_nested_import`. Generates an Import statement, that can be used to fake nested imports. """ i = self.import_stmt # This is not an existing Import statement. Therefore, set position to # 0 (0 is not a valid line number). zero = (0, 0) names = i.namespace.names[1:] n = pr.Name(i._sub_module, names, zero, zero, self.import_stmt) new = pr.Import(i._sub_module, zero, zero, n) new.parent = parent debug.dbg('Generated a nested import: %s' % new) return new
def get_defined_names(self): """ Returns a list of names that define a generator, which can return the content of a generator. """ names = [] none_pos = (0, 0) executes_generator = ('__next__', 'send') for n in ('close', 'throw') + executes_generator: name = pr.Name(builtin.Builtin.scope, [(n, none_pos)], none_pos, none_pos) if n in executes_generator: name.parent = self names.append(name) debug.dbg('generator names', names) return names
def _simple_complete(self, path, like): user_stmt = self._user_stmt(True) is_simple_path = not path or re.search('^[\w][\w\d.]*$', path) if isinstance(user_stmt, pr.Import) or not is_simple_path: return super(type(self), self)._simple_complete(path, like) else: class NamespaceModule: def __getattr__(_, name): for n in self.namespaces: try: return n[name] except KeyError: pass raise AttributeError() def __dir__(_): return list( set( chain.from_iterable(n.keys() for n in self.namespaces))) paths = path.split('.') if path else [] namespaces = (NamespaceModule(), builtins) for p in paths: old, namespaces = namespaces, [] for n in old: try: namespaces.append(getattr(n, p)) except AttributeError: pass completions = [] for n in namespaces: for name in dir(n): if name.lower().startswith(like.lower()): scope = self._parser.module n = pr.Name(self._parser.module, [(name, (0, 0))], (0, 0), (0, 0), scope) completions.append((n, scope)) return completions
def _parse_function(self): """ The parser for a text functions. Process the tokens, which follow a function definition. :return: Return a Scope representation of the tokens. :rtype: Function """ first_pos = self.start_pos token_type, fname = self.next() if token_type != tokenize.NAME: return None fname = pr.Name(self.module, [(fname, self.start_pos)], self.start_pos, self.end_pos) token_type, open = self.next() if open != '(': return None params = self._parse_parentheses() token_type, colon = self.next() annotation = None if colon in ['-', '->']: # parse annotations if colon == '-': # The Python 2 tokenizer doesn't understand this token_type, colon = self.next() if colon != '>': return None annotation, colon = self._parse_statement(added_breaks=[':']) if colon != ':': return None # because of 2 line func param definitions scope = pr.Function(self.module, fname, params, first_pos, annotation) if self.user_scope and scope != self.user_scope \ and self.user_position > first_pos: self.user_scope = scope return scope
def _parse_dot_name(self, pre_used_token=None): """ The dot name parser parses a name, variable or function and returns their names. :return: Tuple of Name, token_type, nexttoken. :rtype: tuple(Name, int, str) """ def append(el): names.append(el) self.module.temp_used_names.append(el[0]) names = [] if pre_used_token is None: token_type, tok = self.next() if token_type != tokenize.NAME and tok != '*': return [], token_type, tok else: token_type, tok = pre_used_token if token_type != tokenize.NAME and tok != '*': # token maybe a name or star return None, token_type, tok append((tok, self.start_pos)) first_pos = self.start_pos while True: token_type, tok = self.next() if tok != '.': break token_type, tok = self.next() if token_type != tokenize.NAME: break append((tok, self.start_pos)) n = pr.Name(self.module, names, first_pos, self.end_pos) if names \ else None return n, token_type, tok
def generate_name(name): return pr.Name(self.GlobalNamespace, [(name, inf_pos)], inf_pos, inf_pos, self.import_stmt)