def source_to_unicode(source, encoding=None): def detect_encoding(): """ For the implementation of encoding definitions in Python, look at: - http://www.python.org/dev/peps/pep-0263/ - http://docs.python.org/2/reference/lexical_analysis.html#encoding-declarations """ byte_mark = literal_eval(r"b'\xef\xbb\xbf'") if source.startswith(byte_mark): # UTF-8 byte-order mark return 'utf-8' first_two_lines = re.match(br'(?:[^\n]*\n){0,2}', source).group(0) possible_encoding = re.search(br"coding[=:]\s*([-\w.]+)", first_two_lines) if possible_encoding: return possible_encoding.group(1) else: # the default if nothing else has been set -> PEP 263 return encoding if encoding is not None else 'utf-8' if isinstance(source, unicode): # only cast str/bytes return source encoding = detect_encoding() if not isinstance(encoding, unicode): encoding = unicode(encoding, 'utf-8', 'replace') # cast to unicode by default return unicode(source, encoding, 'replace')
def description(self): """ A description of the :class:`.Definition` object, which is heavily used in testing. e.g. for ``isinstance`` it returns ``def isinstance``. """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, pr.Name): d = d.parent if isinstance(d, er.Array): d = 'class ' + d.type elif isinstance(d, (pr.Class, er.Class, er.Instance)): d = 'class ' + unicode(d.name) elif isinstance(d, (er.Function, pr.Function)): d = 'def ' + unicode(d.name) elif isinstance(d, pr.Module): # only show module name d = 'module %s' % self.module_name elif self.is_keyword: d = 'keyword %s' % d.name else: d = d.get_code().replace('\n', '') return d
def _check_isinstance_type(evaluator, stmt, search_name_part): try: expression_list = stmt.expression_list() # this might be removed if we analyze and, etc assert len(expression_list) == 1 call = expression_list[0] assert isinstance(call, pr.Call) and str(call.name) == 'isinstance' assert bool(call.execution) # isinstance check isinst = call.execution.values assert len(isinst) == 2 # has two params obj, classes = [statement.expression_list() for statement in isinst] assert len(obj) == 1 assert len(classes) == 1 assert isinstance(obj[0], pr.Call) # names fit? assert unicode(obj[0].name) == unicode(search_name_part) assert isinstance(classes[0], pr.StatementElement) # can be type or tuple except AssertionError: return [] result = [] for c in evaluator.eval_call(classes[0]): for typ in (c.get_index_types() if isinstance(c, iterable.Array) else [c]): result += evaluator.execute(typ) return result
def name(self): """ Name of variable/function/class/module. For example, for ``x = None`` it returns ``'x'``. :rtype: str or None """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, pr.Name): return d.names[-1] if d.names else None elif isinstance(d, er.Array): return unicode(d.type) elif isinstance(d, (pr.Class, er.Class, er.Instance, er.Function, pr.Function)): return unicode(d.name) elif isinstance(d, pr.Module): return self.module_name elif isinstance(d, pr.Import): try: return d.get_defined_names()[0].names[-1] except (AttributeError, IndexError): return None elif isinstance(d, pr.Statement): try: return d.assignment_details[0][1].values[0][0].name.names[-1] except IndexError: return None return None
def in_iterable(name, iterable): """ checks if the name is in the variable 'iterable'. """ for i in iterable: # Only the last name is important, because these names have a # maximal length of 2, with the first one being `self`. if unicode(i.names[-1]) == unicode(name.names[-1]): return True return False
def test_multibyte_script(self): """ `jedi.Script` must accept multi-byte string source. """ try: code = unicode("import datetime; datetime.d") comment = utf8("# multi-byte comment あいうえおä") s = (unicode('%s\n%s') % (code, comment)).encode('utf-8') except NameError: pass # python 3 has no unicode method else: assert len(self.completions(s, (1, len(code))))
def _goto(self, add_import_name=False): """ Used for goto_assignments and usages. :param add_import_name: Add the the name (if import) to the result. """ def follow_inexistent_imports(defs): """ Imports can be generated, e.g. following `multiprocessing.dummy` generates an import dummy in the multiprocessing module. The Import doesn't exist -> follow. """ definitions = set(defs) for d in defs: if isinstance(d.parent, pr.Import) \ and d.start_pos == (0, 0): i = imports.ImportPath(self._evaluator, d.parent).follow(is_goto=True) definitions.remove(d) definitions |= follow_inexistent_imports(i) return definitions goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() user_stmt = self._parser.user_stmt() if next(context) in ('class', 'def'): user_scope = self._parser.user_scope() definitions = set([user_scope.name]) search_name = unicode(user_scope.name) elif isinstance(user_stmt, pr.Import): s, name_part = helpers.get_on_import_stmt(self._evaluator, self._user_context, user_stmt) try: definitions = [s.follow(is_goto=True)[0]] except IndexError: definitions = [] search_name = unicode(name_part) if add_import_name: import_name = user_stmt.get_defined_names() # imports have only one name if not user_stmt.star \ and name_part == import_name[0].names[-1]: definitions.append(import_name[0]) else: stmt = self._get_under_cursor_stmt(goto_path) defs, search_name = self._evaluator.goto(stmt) definitions = follow_inexistent_imports(defs) if isinstance(user_stmt, pr.Statement): c = user_stmt.expression_list() if c and not isinstance(c[0], (str, unicode)) \ and c[0].start_pos > self._pos \ and not re.search(r'\.\w+$', goto_path): # The cursor must be after the start, otherwise the # statement is just an assignee. definitions = [user_stmt] return definitions, search_name
def _goto(self, add_import_name=False): """ Used for goto_assignments and usages. :param add_import_name: TODO add description """ def follow_inexistent_imports(defs): """ Imports can be generated, e.g. following `multiprocessing.dummy` generates an import dummy in the multiprocessing module. The Import doesn't exist -> follow. """ definitions = set(defs) for d in defs: if isinstance(d.parent, pr.Import) \ and d.start_pos == (0, 0): i = imports.ImportPath(d.parent).follow(is_goto=True) definitions.remove(d) definitions |= follow_inexistent_imports(i) return definitions goto_path = self._module.get_path_under_cursor() context = self._module.get_context() user_stmt = self._parser.user_stmt if next(context) in ('class', 'def'): user_scope = self._parser.user_scope definitions = set([user_scope.name]) search_name = unicode(user_scope.name) elif isinstance(user_stmt, pr.Import): s, name_part = self._get_on_import_stmt() try: definitions = [s.follow(is_goto=True)[0]] except IndexError: definitions = [] search_name = unicode(name_part) if add_import_name: import_name = user_stmt.get_defined_names() # imports have only one name if name_part == import_name[0].names[-1]: definitions.append(import_name[0]) else: stmt = self._get_under_cursor_stmt(goto_path) defs, search_name = evaluate.goto(stmt) definitions = follow_inexistent_imports(defs) if isinstance(user_stmt, pr.Statement): call = user_stmt.get_commands()[0] if not isinstance(call, (str, unicode)) and \ call.start_pos > self.pos: # The cursor must be after the start, otherwise the # statement is just an assignee. definitions = [user_stmt] return definitions, search_name
def has_explicit_absolute_import(self): """ Checks if imports in this module are explicitly absolute, i.e. there is a ``__future__`` import. """ for imp in self.imports: if imp.from_ns is None or imp.namespace is None: continue namespace, feature = imp.from_ns.names[0], imp.namespace.names[0] if unicode(namespace) == "__future__" and unicode(feature) == "absolute_import": return True return False
def description(self): """ A description of the :class:`.Definition` object, which is heavily used in testing. e.g. for ``isinstance`` it returns ``def isinstance``. Example: >>> from jedi import Script >>> source = ''' ... def f(): ... pass ... ... class C: ... pass ... ... variable = f or C''' >>> script = Script(source, column=3) # line is maximum by default >>> defs = script.goto_definitions() >>> defs = sorted(defs, key=lambda d: d.line) >>> defs [<Definition def f>, <Definition class C>] >>> str(defs[0].description) # strip literals in python2 'def f' >>> str(defs[1].description) 'class C' """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, pr.Name): d = d.parent if isinstance(d, er.Array): d = "class " + d.type elif isinstance(d, (pr.Class, er.Class, er.Instance)): d = "class " + unicode(d.name) elif isinstance(d, (er.Function, pr.Function)): d = "def " + unicode(d.name) elif isinstance(d, pr.Module): # only show module name d = "module %s" % self.module_name elif self.is_keyword: d = "keyword %s" % d.name else: code = d.get_code().replace("\n", "") max_len = 20 d = (code[:max_len] + "...") if len(code) > max_len + 3 else code return d
def description(self): """ A description of the :class:`.Definition` object, which is heavily used in testing. e.g. for ``isinstance`` it returns ``def isinstance``. Example: >>> from jedi import Script >>> source = ''' ... def f(): ... pass ... ... class C: ... pass ... ... variable = f or C''' >>> script = Script(source, column=3) # line is maximum by default >>> defs = script.goto_definitions() >>> defs = sorted(defs, key=lambda d: d.line) >>> defs [<Definition def f>, <Definition class C>] >>> str(defs[0].description) # strip literals in python2 'def f' >>> str(defs[1].description) 'class C' """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, pr.Name): d = d.parent if isinstance(d, compiled.CompiledObject): d = d.type() + ' ' + d.name elif isinstance(d, iterable.Array): d = 'class ' + d.type elif isinstance(d, (pr.Class, er.Class, er.Instance)): d = 'class ' + unicode(d.name) elif isinstance(d, (er.Function, pr.Function)): d = 'def ' + unicode(d.name) elif isinstance(d, pr.Module): # only show module name d = 'module %s' % self.module_name elif self.is_keyword: d = 'keyword %s' % d.name else: d = d.get_code().replace('\n', '').replace('\r', '') return d
def assemble(command_list, assignment=None): pieces = [c.get_code() if isinstance(c, Simple) else c.string if isinstance(c, (tokenize.Token, Operator)) else unicode(c) for c in command_list] if assignment is None: return ''.join(pieces) return '%s %s ' % (''.join(pieces), assignment)
def raw_doc(self): """ Returns a cleaned version of the docstring token. """ try: # Returns a literal cleaned version of the ``Token``. return unicode(cleandoc(literal_eval(self._doc_token.string))) except AttributeError: return u('')
def get_call_signature(self, width=72, funcname=None): """ Generate call signature of this function. :param width: Fold lines if a line is longer than this value. :type width: int :arg funcname: Override function name when given. :type funcname: str :rtype: str """ l = unicode(funcname or self.name.names[-1]) + '(' lines = [] for (i, p) in enumerate(self.params): code = p.get_code(False) if i != len(self.params) - 1: code += ', ' if len(l + code) > width: lines.append(l[:-1] if l[-1] == ' ' else l) l = code else: l += code if l: lines.append(l) lines[-1] += ')' return '\n'.join(lines)
def description(self): """ A textual description of the object. Example: >>> from jedi import Script >>> source = ''' ... def f(): ... pass ... ... class C: ... pass ... ... variable = f or C''' >>> script = Script(source, len(source.splitlines()), 3, 'example.py') >>> defs = script.definition() # doctest: +SKIP >>> defs = sorted(defs, key=lambda d: d.line) # doctest: +SKIP >>> defs # doctest: +SKIP [<Definition def f>, <Definition class C>] >>> defs[0].description # doctest: +SKIP 'def f' >>> defs[1].description # doctest: +SKIP 'class C' """ return unicode(self._definition)
def _get_buildout_scripts(module_path): """ if there is a 'buildout.cfg' file in one of the parent directories of the given module it will return a list of all files in the buildout bin directory that look like python files. :param module_path: absolute path to the module. :type module_path: str """ project_root = _get_parent_dir_with_file(module_path, 'buildout.cfg') if not project_root: return [] bin_path = os.path.join(project_root, 'bin') if not os.path.exists(bin_path): return [] extra_module_paths = [] for filename in os.listdir(bin_path): try: filepath = os.path.join(bin_path, filename) with open(filepath, 'r') as f: firstline = f.readline() if firstline.startswith('#!') and 'python' in firstline: extra_module_paths.append(filepath) except IOError as e: # either permission error or race cond. because file got deleted # ignore debug.warning(unicode(e)) continue return extra_module_paths
def collect_dir_tests(base_dir, test_files, check_thirdparty=False): for f_name in os.listdir(base_dir): files_to_execute = [a for a in test_files.items() if f_name.startswith(a[0])] lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, []) if f_name.endswith(".py") and (not test_files or files_to_execute): skip = None if check_thirdparty: lib = f_name.replace('_.py', '') try: # there is always an underline at the end. # It looks like: completion/thirdparty/pylab_.py __import__(lib) except ImportError: skip = 'Thirdparty-Library %s not found.' % lib path = os.path.join(base_dir, f_name) if is_py3: source = open(path, encoding='utf-8').read() else: source = unicode(open(path).read(), 'UTF-8') for case in collect_file_tests(path, StringIO(source), lines_to_execute): case.source = source if skip: case.set_skip(skip) yield case
def full_name(self): """ Dot-separated path of this object. It is in the form of ``<module>[.<submodule>[...]][.<object>]``. It is useful when you want to look up Python manual of the object at hand. Example: >>> from jedi import Script >>> source = ''' ... import os ... os.path.join''' >>> script = Script(source, 3, len('os.path.join'), 'example.py') >>> print(script.goto_definitions()[0].full_name) os.path.join Notice that it correctly returns ``'os.path.join'`` instead of (for example) ``'posixpath.join'``. """ path = [unicode(p) for p in self._path()] # TODO add further checks, the mapping should only occur on stdlib. if not path: return None # for keywords the path is empty with common.ignored(KeyError): path[0] = self._mapping[path[0]] for key, repl in self._tuple_mapping.items(): if tuple(path[:len(key)]) == key: path = [repl] + path[len(key):] return '.'.join(path if path[0] else path[1:])
def _remove_statements(self, stmt): """ This is the part where statements are being stripped. Due to lazy evaluation, statements like a = func; b = a; b() have to be evaluated. """ evaluator = self._evaluator types = [] # Remove the statement docstr stuff for now, that has to be # implemented with the evaluator class. #if stmt.docstr: #res_new.append(stmt) check_instance = None if isinstance(stmt, er.InstanceElement) and stmt.is_class_var: check_instance = stmt.instance stmt = stmt.var types += evaluator.eval_statement(stmt, seek_name=unicode(self.name_str)) if check_instance is not None: # class renames types = [er.InstanceElement(evaluator, check_instance, a, True) if isinstance(a, (er.Function, pr.Function)) else a for a in types] return types
def _load_faked_module(module): module_name = module.__name__ if module_name == '__builtin__' and not is_py3: module_name = 'builtins' try: return modules[module_name] except KeyError: path = os.path.dirname(os.path.abspath(__file__)) try: with open(os.path.join(path, 'fake', module_name) + '.pym') as f: source = f.read() except IOError: modules[module_name] = None return modules[module_name] = m = parse(unicode(source)) if module_name == 'builtins' and not is_py3: # There are two implementations of `open` for either python 2/3. # -> Rename the python2 version (`look at fake/builtins.pym`). open_func = _search_scope(m, 'open') open_func.children[1].value = 'open_python3' open_func = _search_scope(m, 'open_python2') open_func.children[1].value = 'open' return m
def raw_doc(self): """ Returns a cleaned version of the docstring token. """ if isinstance(self, Module): node = self.children[0] elif isinstance(self, ClassOrFunc): node = self.children[self.children.index(':') + 1] if is_node(node, 'suite'): # Normally a suite node = node.children[2] # -> NEWLINE INDENT stmt else: # ExprStmt simple_stmt = self.parent c = simple_stmt.parent.children index = c.index(simple_stmt) if not index: return '' node = c[index - 1] if is_node(node, 'simple_stmt'): node = node.children[0] if node.type == 'string': # TODO We have to check next leaves until there are no new # leaves anymore that might be part of the docstring. A # docstring can also look like this: ``'foo' 'bar' # Returns a literal cleaned version of the ``Token``. cleaned = cleandoc(literal_eval(node.value)) # Since we want the docstr output to be always unicode, just # force it. if is_py3 or isinstance(cleaned, unicode): return cleaned else: return unicode(cleaned, 'UTF-8', 'replace') return ''
def usages(evaluator, definition_names, mods): """ :param definitions: list of Name """ def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result search_name = unicode(list(definition_names)[0]) compare_definitions = compare_array(definition_names) mods |= set([d.get_parent_until() for d in definition_names]) definitions = [] for m in imports.get_modules_containing_name(evaluator, mods, search_name): try: check_names = m.used_names[search_name] except KeyError: continue for name in check_names: result = evaluator.goto(name) if [c for c in compare_array(result) if c in compare_definitions]: definitions.append(classes.Definition(evaluator, name)) # Previous definitions might be imports, so include them # (because goto might return that import name). compare_definitions += compare_array([name]) return definitions
def _load_faked_module(evaluator, module_name): try: return fake_modules[module_name] except KeyError: pass check_module_name = module_name if module_name == '__builtin__' and evaluator.environment.version_info.major == 2: check_module_name = 'builtins' try: path = _path_dict[check_module_name] except KeyError: fake_modules[module_name] = None return with open(path) as f: source = f.read() fake_modules[module_name] = m = evaluator.latest_grammar.parse(unicode(source)) if check_module_name != module_name: # There are two implementations of `open` for either python 2/3. # -> Rename the python2 version (`look at fake/builtins.pym`). open_func = _search_scope(m, 'open') open_func.children[1].value = 'open_python3' open_func = _search_scope(m, 'open_python2') open_func.children[1].value = 'open' return m
def _fix_forward_reference(context, node): evaled_nodes = context.eval_node(node) if len(evaled_nodes) != 1: debug.warning("Eval'ed typing index %s should lead to 1 object, " " not %s" % (node, evaled_nodes)) return node evaled_node = list(evaled_nodes)[0] if isinstance(evaled_node, compiled.CompiledObject) and \ isinstance(evaled_node.obj, str): try: new_node = context.evaluator.grammar.parse( _compatibility.unicode(evaled_node.obj), start_symbol='eval_input', error_recovery=False ) except ParserSyntaxError: debug.warning('Annotation not parsed: %s' % evaled_node.obj) return node else: module = node.get_root_node() parser_utils.move(new_node, module.end_pos[0]) new_node.parent = context.tree_node return new_node else: return node
def _does_scope_break_immediately(self, scope, name_list_scope): """ In comparison to everthing else, if/while/etc doesn't break directly, because there are multiple different places in which a variable can be defined. """ if isinstance(scope, pr.Flow) \ or isinstance(scope, pr.KeywordStatement) and scope.name == 'global': # Check for `if foo is not None`, because Jedi is not interested in # None values, so this is the only branch we actually care about. # ATM it carries the same issue as the isinstance checks. It # doesn't work with instance variables (self.foo). if isinstance(scope, pr.Flow) and scope.command in ('if', 'while'): try: expression_list = scope.inputs[0].expression_list() except IndexError: pass else: p = precedence.create_precedence(expression_list) if (isinstance(p, precedence.Precedence) and p.operator.string == 'is not' and p.right.get_code() == 'None' and p.left.get_code() == unicode(self.name_str)): return True if isinstance(name_list_scope, er.Class): name_list_scope = name_list_scope.base return scope == name_list_scope else: return True
def _get_buildout_script_paths(search_path): """ if there is a 'buildout.cfg' file in one of the parent directories of the given module it will return a list of all files in the buildout bin directory that look like python files. :param search_path: absolute path to the module. :type search_path: str """ project_root = _get_parent_dir_with_file(search_path, 'buildout.cfg') if not project_root: return bin_path = os.path.join(project_root, 'bin') if not os.path.exists(bin_path): return for filename in os.listdir(bin_path): try: filepath = os.path.join(bin_path, filename) with open(filepath, 'r') as f: firstline = f.readline() if firstline.startswith('#!') and 'python' in firstline: yield filepath except (UnicodeDecodeError, IOError) as e: # Probably a binary file; permission error or race cond. because # file got deleted. Ignore it. debug.warning(unicode(e)) continue
def usages(self, additional_module_paths=()): """ Return :class:`api_classes.Usage` objects, which contain all names that point to the definition of the name under the cursor. This is very useful for refactoring (renaming), or to show all usages of a variable. .. todo:: Implement additional_module_paths :rtype: list of :class:`api_classes.Usage` """ user_stmt = self._parser.user_stmt definitions, search_name = self._goto(add_import_name=True) if isinstance(user_stmt, pr.Statement) \ and self.pos < user_stmt.get_commands()[0].start_pos: # the search_name might be before `=` definitions = [v for v in user_stmt.set_vars if unicode(v.names[-1]) == search_name] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = dynamic.usages_add_import_modules(definitions, search_name) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module) names = dynamic.usages(definitions, search_name, module) for d in set(definitions): if isinstance(d, pr.Module): names.append(api_classes.Usage(d, d)) else: names.append(api_classes.Usage(d.names[-1], d)) return self._sorted_defs(set(names))
def _load_faked_module(module): module_name = module.__name__ if module_name == '__builtin__' and not is_py3: module_name = 'builtins' try: return modules[module_name] except KeyError: path = os.path.dirname(os.path.abspath(__file__)) try: with open(os.path.join(path, 'fake', module_name) + '.pym') as f: source = f.read() except IOError: modules[module_name] = None return grammar = load_grammar(version='3.4') module = ParserWithRecovery(grammar, unicode(source), module_name).module modules[module_name] = module if module_name == 'builtins' and not is_py3: # There are two implementations of `open` for either python 2/3. # -> Rename the python2 version (`look at fake/builtins.pym`). open_func = search_scope(module, 'open') open_func.children[1] = FakeName('open_python3') open_func = search_scope(module, 'open_python2') open_func.children[1] = FakeName('open') return module
def name(self): """ Name of variable/function/class/module. For example, for ``x = None`` it returns ``'x'``. :rtype: str or None """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, (compiled.CompiledObject, compiled.CompiledName)): name = d.name elif isinstance(d, pr.Name): name = d.names[-1] elif isinstance(d, iterable.Array): name = d.type elif isinstance(d, (pr.Class, er.Class, er.Instance, er.Function, pr.Function)): name = d.name elif isinstance(d, pr.Module): name = self.module_name elif isinstance(d, pr.Import): try: name = d.get_defined_names()[0].names[-1] except (AttributeError, IndexError): return None elif isinstance(d, pr.Statement): try: expression_list = d.assignment_details[0][0] name = expression_list[0].name.names[-1] except IndexError: if isinstance(d, pr.Param): try: return unicode(d.expression_list()[0].name) except (IndexError, AttributeError): # IndexError for syntax error params # AttributeError for *args/**kwargs pass return None elif isinstance(d, iterable.Generator): return None elif isinstance(d, pr.NamePart): name = d return unicode(name)
def _get_module(self): cache.invalidate_star_import_cache(self._path) parser = FastParser(self._grammar, self._source, self.path) save_parser(self.path, parser, pickling=False) module = self._evaluator.wrap(parser.module) imports.add_module(self._evaluator, unicode(module.name), module) return parser.module
def description(self): """Provide a description of the completion object.""" if self._definition is None: return '' t = self.type if t == 'statement' or t == 'import': desc = self._definition.get_code() else: desc = '.'.join(unicode(p) for p in self._path()) line = '' if self.in_builtin_module else '@%s' % self.line return '%s: %s%s' % (t, desc, line)
def follow(self, is_goto=False): if self._evaluator.recursion_detector.push_stmt(self._import): # check recursion return [] try: module = self._evaluator.wrap(self._import.get_parent_until()) import_path = self._import.path_for_name(self._name) from_import_name = None try: from_names = self._import.get_from_names() except AttributeError: # Is an import_name pass else: if len(from_names) + 1 == len(import_path): # We have to fetch the from_names part first and then check # if from_names exists in the modules. from_import_name = import_path[-1] import_path = from_names importer = Importer(self._evaluator, tuple(import_path), module, self._import.level) types = importer.follow() #if self._import.is_nested() and not self.nested_resolve: # scopes = [NestedImportModule(module, self._import)] if from_import_name is not None: types = list( chain.from_iterable( self._evaluator.find_types( t, unicode(from_import_name), is_goto=is_goto) for t in types)) if not types: path = import_path + [from_import_name] importer = Importer(self._evaluator, tuple(path), module, self._import.level) types = importer.follow() # goto only accepts `Name` if is_goto: types = [s.name for s in types] else: # goto only accepts `Name` if is_goto: types = [s.name for s in types] debug.dbg('after import: %s', types) finally: self._evaluator.recursion_detector.pop_stmt() return types
def _get_typing_replacement_module(): """ The idea is to return our jedi replacement for the PEP-0484 typing module as discussed at https://github.com/davidhalter/jedi/issues/663 """ global _typing_module if _typing_module is None: typing_path = \ os.path.abspath(os.path.join(__file__, "../jedi_typing.py")) with open(typing_path) as f: code = _compatibility.unicode(f.read()) _typing_module = parse(code) return _typing_module
def _handle_for_loops(self, loop): # Take the first statement (for has always only # one, remember `in`). And follow it. if not loop.inputs: return [] result = iterable.get_iterator_types( self._evaluator.eval_statement(loop.inputs[0])) if len(loop.set_vars) > 1: expression_list = loop.set_stmt.expression_list() # loops with loop.set_vars > 0 only have one command result = _assign_tuples(expression_list[0], result, unicode(self.name_str)) return result
def sys_path_with_modifications(self): # If you edit e.g. gunicorn, there will be imports like this: # `from gunicorn import something`. But gunicorn is not in the # sys.path. Therefore look if gunicorn is a parent directory, #56. in_path = [] if self.import_path and self.file_path is not None: parts = self.file_path.split(os.path.sep) for i, p in enumerate(parts): if p == unicode(self.import_path[0]): new = os.path.sep.join(parts[:i]) in_path.append(new) return in_path + sys_path_with_modifications(self._evaluator, self.module)
def get_posibilities(evaluator, module, func_name): try: possible_stmts = module.used_names[func_name] except KeyError: return [] for stmt in possible_stmts: if isinstance(stmt, pr.Import): continue calls = helpers.scan_statement_for_calls(stmt, func_name) for c in calls: # no execution means that params cannot be set call_path = list(c.generate_call_path()) pos = c.start_pos scope = stmt.parent # this whole stuff is just to not execute certain parts # (speed improvement), basically we could just call # ``eval_call_path`` on the call_path and it would # also work. def listRightIndex(lst, value): return len(lst) - lst[-1::-1].index(value) - 1 # Need to take right index, because there could be a # func usage before. call_path_simple = [unicode(d) if isinstance(d, pr.NamePart) else d for d in call_path] i = listRightIndex(call_path_simple, func_name) first, last = call_path[:i], call_path[i + 1:] if not last and not call_path_simple.index(func_name) != i: continue scopes = [scope] if first: scopes = evaluator.eval_call_path(iter(first), scope, pos) pos = None from jedi.evaluate import representation as er for scope in scopes: s = evaluator.find_types(scope, func_name, position=pos, search_global=not first, resolve_decorator=False) c = [getattr(escope, 'base_func', None) or escope.base for escope in s if escope.isinstance(er.Function, er.Class)] if compare in c: # only if we have the correct function we execute # it, otherwise just ignore it. evaluator.follow_path(iter(last), s, scope) return listener.param_possibilities
def infer_import(context, tree_name, is_goto=False): module_context = context.get_root_context() import_node = tree_name.get_parent_until(tree.Import) import_path = import_node.path_for_name(tree_name) from_import_name = None evaluator = context.evaluator try: from_names = import_node.get_from_names() except AttributeError: # Is an import_name pass else: if len(from_names) + 1 == len(import_path): # We have to fetch the from_names part first and then check # if from_names exists in the modules. from_import_name = import_path[-1] import_path = from_names importer = Importer(evaluator, tuple(import_path), module_context, import_node.level) types = importer.follow() #if import_node.is_nested() and not self.nested_resolve: # scopes = [NestedImportModule(module, import_node)] if from_import_name is not None: types = unite( t.py__getattribute__( unicode(from_import_name), name_context=context, is_goto=is_goto ) for t in types ) if not types: path = import_path + [from_import_name] importer = Importer(evaluator, tuple(path), module_context, import_node.level) types = importer.follow() # goto only accepts `Name` if is_goto: types = set(s.name for s in types) else: # goto only accepts `Name` if is_goto: types = set(s.name for s in types) debug.dbg('after import: %s', types) return types
def _get_typing_replacement_module(grammar): """ The idea is to return our jedi replacement for the PEP-0484 typing module as discussed at https://github.com/davidhalter/jedi/issues/663 """ global _typing_module, _typing_module_code_lines if _typing_module is None: typing_path = \ os.path.abspath(os.path.join(__file__, "../jedi_typing.py")) with open(typing_path) as f: code = unicode(f.read()) _typing_module = grammar.parse(code) _typing_module_code_lines = split_lines(code, keepends=True) return _typing_module, _typing_module_code_lines
def _get_nested_import_name(self): """ Generates an Import statement, that can be used to fake nested imports. """ i = self._nested_import # This is not an existing Import statement. Therefore, set position to # 0 (0 is not a valid line number). zero = (0, 0) names = [unicode(name) for name in i.namespace_names[1:]] name = helpers.FakeName(names, self._nested_import) new = tree.Import(i._sub_module, zero, zero, name) new.parent = self._module debug.dbg('Generated a nested import: %s', new) return helpers.FakeName(str(i.namespace_names[1]), new)
def _follow_statements_imports(self): # imports completion is very complicated and needs to be treated # separately in Completion. if self._definition.isinstance( pr.Import) and self._definition.alias is None: i = imports.ImportWrapper(self._evaluator, self._definition, True) import_path = i.import_path + (unicode(self._name), ) try: return imports.get_importer(self._evaluator, import_path, i._importer.module).follow( self._evaluator) except imports.ModuleNotFound: pass return super(Completion, self)._follow_statements_imports()
def call_signatures(self): """ Return the function object of the call you're currently in. E.g. if the cursor is here:: abs(# <-- cursor is here This would return the ``abs`` function. On the other hand:: abs()# <-- cursor is here This would return ``None``. :rtype: list of :class:`classes.CallSignature` """ user_stmt = self._parser.user_stmt_with_whitespace() call, index = search_call_signatures(user_stmt, self._pos) if call is None: return [] stmt_el = call while isinstance(stmt_el.parent, pr.StatementElement): # Go to parent literal/variable until not possible anymore. This # makes it possible to return the whole expression. stmt_el = stmt_el.parent # We can reset the execution since it's a new object # (fast_parent_copy). execution_arr, call.execution = call.execution, None with common.scale_speed_settings(settings.scale_call_signatures): _callable = lambda: self._evaluator.eval_call(stmt_el) origins = cache.cache_call_signatures(_callable, self.source, self._pos, user_stmt) debug.speed('func_call followed') key_name = None try: detail = execution_arr[index].assignment_details[0] except IndexError: pass else: try: key_name = unicode(detail[0][0].name) except (IndexError, AttributeError): pass return [ classes.CallSignature(self._evaluator, o, call, index, key_name) for o in origins if o.is_callable() ]
def get_call_signature(self, width=72, func_name=None): """ Generate call signature of this function. :param width: Fold lines if a line is longer than this value. :type width: int :arg func_name: Override function name when given. :type func_name: str :rtype: str """ func_name = func_name or self.name code = unicode(func_name) + self._get_paramlist_code() return '\n'.join(textwrap.wrap(code, width))
def test_unicode_script(self): """ normally no unicode objects are being used. (<=2.7) """ s = unicode("import datetime; datetime.timedelta") completions = self.complete(s) assert len(completions) assert type(completions[0].description) is unicode s = utf8("author='öä'; author") completions = self.complete(s) assert type(completions[0].description) is unicode s = utf8("#-*- coding: iso-8859-1 -*-\nauthor='öä'; author") s = s.encode('latin-1') completions = self.complete(s) assert type(completions[0].description) is unicode
def get_code(self): if self.type == Call.NAME: s = self.name.get_code() else: if not is_py3k and isinstance(self.name, str)\ and "'" not in self.name: # This is a very rough spot, because of repr not supporting # unicode signs, see `test_unicode_script`. s = "'%s'" % unicode(self.name, 'UTF-8') else: s = '' if self.name is None else repr(self.name) if self.execution is not None: s += self.execution.get_code() if self.next is not None: s += '.' + self.next.get_code() return s
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 = [(unicode(name_part), name_part.start_pos) for name_part in 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 description(self): """ Provide a description of the completion object. .. todo:: return value is just __repr__ of some objects, improve! """ parent = self._name.parent if parent is None: return '' t = self.type if t == 'Statement' or t == 'Import': desc = self._definition.get_code(False) else: desc = '.'.join(unicode(p) for p in self.path) line = '' if self.in_builtin_module else '@%s' % self.line return '%s: %s%s' % (t, desc, line)
def _paths_from_call_expression(module_path, call): """ extract the path from either "sys.path.append" or "sys.path.insert" """ if call.execution is None: return n = call.name if not isinstance(n, pr.Name) or len(n.names) != 3: return names = [unicode(x) for x in n.names] if names[:2] != ['sys', 'path']: return cmd = names[2] exe = call.execution if cmd == 'insert' and len(exe) == 2: path = _paths_from_insert(module_path, exe) elif cmd == 'append' and len(exe) == 1: path = _execute_code(module_path, exe.get_code()) return path and [path] or []
def filter_name(self, scope_generator): """ Filters all variables of a scope (which are defined in the `scope_generator`), until the name fits. """ result = [] for nscope, name_list in scope_generator: break_scopes = [] if not isinstance(nscope, compiled.CompiledObject): # Here is the position stuff happening (sorting of variables). # Compiled objects don't need that, because there's only one # reference. name_list = sorted(name_list, key=lambda n: n.start_pos, reverse=True) for name in name_list: if unicode(self.name_str) != name.get_code(): continue parpar = name.parent.parent if name.parent.parent in break_scopes: continue if not self._name_is_array_assignment(name): result.append(name) # `arr[1] =` is not the definition # for comparison we need the raw class # this means that a definition was found and is not e.g. # in if/else. if result and self._name_is_break_scope(name): #print result, name.parent, parpar, s if isinstance(parpar, pr.Flow) \ or isinstance(parpar, pr.KeywordStatement) \ and parpar.name == 'global': s = nscope.base if isinstance(nscope, er.Class) else nscope if parpar == s: break else: break break_scopes.append(parpar) if result: break debug.dbg('finder.filter_name "%s" in (%s-%s): %s@%s', self.name_str, self.scope, nscope, u(result), self.position) return result
def usages(self, additional_module_paths=()): """ Return :class:`classes.Usage` objects, which contain all names that point to the definition of the name under the cursor. This is very useful for refactoring (renaming), or to show all usages of a variable. .. todo:: Implement additional_module_paths :rtype: list of :class:`classes.Usage` """ temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False user_stmt = self._parser.user_stmt() definitions, search_name = self._goto(add_import_name=True) if isinstance(user_stmt, pr.Statement): c = user_stmt.expression_list()[0] if not isinstance(c, unicode) and self._pos < c.start_pos: # the search_name might be before `=` definitions = [ v for v in user_stmt.get_set_vars() if unicode(v.names[-1]) == search_name ] if not isinstance(user_stmt, pr.Import): # import case is looked at with add_import_name option definitions = usages.usages_add_import_modules( self._evaluator, definitions, search_name) module = set([d.get_parent_until() for d in definitions]) module.add(self._parser.module()) names = usages.usages(self._evaluator, definitions, search_name, module) for d in set(definitions): if isinstance(d, pr.Module): names.append(usages.Usage(self._evaluator, d, d)) elif isinstance(d, er.Instance): # Instances can be ignored, because they have been created by # ``__getattr__``. pass else: names.append(usages.Usage(self._evaluator, d.names[-1], d)) settings.dynamic_flow_information = temp return helpers.sorted_definitions(set(names))
def collections_namedtuple(evaluator, obj, arguments): """ Implementation of the namedtuple function. This has to be done by processing the namedtuple class template and evaluating the result. .. note:: |jedi| only supports namedtuples on Python >2.6. """ # Namedtuples are not supported on Python 2.6 if not hasattr(collections, '_class_template'): return set() # Process arguments # TODO here we only use one of the types, we should use all. name = list(_follow_param(evaluator, arguments, 0))[0].obj _fields = list(_follow_param(evaluator, arguments, 1))[0] if isinstance(_fields, compiled.CompiledObject): fields = _fields.obj.replace(',', ' ').split() elif isinstance(_fields, iterable.AbstractSequence): fields = [ v.obj for lazy_context in _fields.py__iter__() for v in lazy_context.infer() if hasattr(v, 'obj') ] else: return set() # Build source source = collections._class_template.format( typename=name, field_names=fields, num_fields=len(fields), arg_list=', '.join(fields), repr_fmt=', '.join( collections._repr_template.format(name=name) for name in fields), field_defs='\n'.join( collections._field_template.format(index=index, name=name) for index, name in enumerate(fields))) # Parse source generated_class = ParserWithRecovery(evaluator.grammar, unicode(source)).module.subscopes[0] return set( [er.ClassContext(evaluator, generated_class, evaluator.BUILTINS)])
def check_calls(calls, add_name): """ Calls are processed here. The part before the call is searched and compared with the original Array. """ result = [] for c in calls: call_path = list(c.generate_call_path()) call_path_simple = [ unicode(n) if isinstance(n, pr.NamePart) else n for n in call_path ] separate_index = call_path_simple.index(add_name) if add_name == call_path_simple[-1] or separate_index == 0: # this means that there is no execution -> [].append # or the keyword is at the start -> append() continue backtrack_path = iter(call_path[:separate_index]) position = c.start_pos scope = c.get_parent_until(pr.IsScope) found = evaluator.eval_call_path(backtrack_path, scope, position) if not compare_array in found: continue params = call_path[separate_index + 1] if not params.values: continue # no params: just ignore it if add_name in ['append', 'add']: for param in params: result += evaluator.eval_statement(param) elif add_name in ['insert']: try: second_param = params[1] except IndexError: continue else: result += evaluator.eval_statement(second_param) elif add_name in ['extend', 'update']: for param in params: iterators = evaluator.eval_statement(param) result += get_iterator_types(iterators) return result
def _eval_param(self, param): evaluator = self._evaluator res_new = [] func = param.parent cls = func.parent.get_parent_until((pr.Class, pr.Function)) from jedi.evaluate.param import ExecutedParam if isinstance(cls, pr.Class) and param.position_nr == 0 \ and not isinstance(param, ExecutedParam): # This is where we add self - if it has never been # instantiated. if isinstance(self.scope, er.InstanceElement): res_new.append(self.scope.instance) else: for inst in evaluator.execute(er.Class(evaluator, cls)): inst.is_generated = True res_new.append(inst) return res_new # Instances are typically faked, if the instance is not called from # outside. Here we check it for __init__ functions and return. if isinstance(func, er.InstanceElement) \ and func.instance.is_generated and str(func.name) == '__init__': param = func.var.params[param.position_nr] # Add docstring knowledge. doc_params = docstrings.follow_param(evaluator, param) if doc_params: return doc_params if not param.is_generated: # Param owns no information itself. res_new += dynamic.search_params(evaluator, param) if not res_new: if param.stars: t = 'tuple' if param.stars == 1 else 'dict' typ = evaluator.find_types(compiled.builtin, t)[0] res_new = evaluator.execute(typ) if not param.assignment_details: # this means that there are no default params, # so just ignore it. return res_new return res_new + evaluator.eval_statement(param, seek_name=unicode(self.name_str))
def _paths_from_assignment(statement): """ extracts the assigned strings from an assignment that looks as follows:: >>> sys.path[0:0] = ['module/path', 'another/module/path'] """ names = statement.get_defined_names() if len(names) != 1: return [] if [unicode(x) for x in names[0].names] != ['sys', 'path']: return [] expressions = statement.expression_list() if len(expressions) != 1 or not isinstance(expressions[0], pr.Array): return stmts = (s for s in expressions[0].values if isinstance(s, pr.Statement)) expression_lists = (s.expression_list() for s in stmts) return [e.value for exprs in expression_lists for e in exprs if isinstance(e, pr.Literal) and e.value]
def collections_namedtuple(evaluator, obj, params): """ Implementation of the namedtuple function. This has to be done by processing the namedtuple class template and evaluating the result. .. note:: |jedi| only supports namedtuples on Python >2.6. """ # Namedtuples are not supported on Python 2.6 if not hasattr(collections, '_class_template'): return [] # Process arguments name = _follow_param(evaluator, params, 0)[0].obj _fields = _follow_param(evaluator, params, 1)[0] if isinstance(_fields, compiled.CompiledObject): fields = _fields.obj.replace(',', ' ').split() elif isinstance(_fields, iterable.Array): try: fields = [v.obj for v in _fields.values()] except AttributeError: return [] else: return [] # Build source source = collections._class_template.format( typename=name, field_names=fields, num_fields=len(fields), arg_list=', '.join(fields), repr_fmt=', '.join( collections._repr_template.format(name=name) for name in fields), field_defs='\n'.join( collections._field_template.format(index=index, name=name) for index, name in enumerate(fields))) # Parse source generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0] return [er.Class(evaluator, generated_class)]
def get_self_attributes(self): def add_self_dot_name(name): """ Need to copy and rewrite the name, because names are now ``instance_usage.variable`` instead of ``self.variable``. """ n = copy.copy(name) n.names = n.names[1:] n._get_code = unicode(n.names[-1]) names.append(InstanceElement(self._evaluator, self, n)) names = [] # This loop adds the names of the self object, copies them and removes # the self. for sub in self.base.subscopes: if isinstance(sub, pr.Class): continue # Get the self name, if there's one. self_name = self._get_func_self_name(sub) if not self_name: continue if sub.name.get_code() == '__init__': # ``__init__`` is special because the params need are injected # this way. Therefore an execution is necessary. if not sub.decorators: # __init__ decorators should generally just be ignored, # because to follow them and their self variables is too # complicated. sub = self._get_method_execution(sub) for n in sub.get_defined_names(): # Only names with the selfname are being added. # It is also important, that they have a len() of 2, # because otherwise, they are just something else if unicode(n.names[0]) == self_name and len(n.names) == 2: add_self_dot_name(n) if not isinstance(self.base, compiled.CompiledObject): for s in self.base.get_super_classes(): for inst in self._evaluator.execute(s): names += inst.get_self_attributes() return names
def find_assignments(lhs, results, seek_name): """ Check if `seek_name` is in the left hand side `lhs` of assignment. `lhs` can simply be a variable (`pr.Call`) or a tuple/list (`pr.Array`) representing the following cases:: a = 1 # lhs is pr.Call (a, b) = 2 # lhs is pr.Array :type lhs: pr.Call :type results: list :type seek_name: str """ if isinstance(lhs, pr.Array): return _assign_tuples(lhs, results, seek_name) elif unicode(lhs.name.names[-1]) == seek_name: return results else: return []
def name(self): """ Name of variable/function/class/module. For example, for ``x = None`` it returns ``'x'``. :rtype: str or None """ d = self._definition if isinstance(d, er.InstanceElement): d = d.var if isinstance(d, (compiled.CompiledObject, compiled.CompiledName)): name = d.name elif isinstance(d, pr.Name): name = d.names[-1] elif isinstance(d, iterable.Array): name = d.type elif isinstance(d, (pr.Class, er.Class, er.Instance, er.Function, pr.Function)): name = d.name elif isinstance(d, pr.Module): name = self.module_name elif isinstance(d, pr.Import): try: name = d.get_defined_names()[0].names[-1] except (AttributeError, IndexError): return None elif isinstance(d, pr.Param): name = d.get_name() elif isinstance(d, pr.Statement): try: expression_list = d.assignment_details[0][0] name = expression_list[0].name.names[-1] except IndexError: return None elif isinstance(d, iterable.Generator): return None elif isinstance(d, pr.NamePart): name = d return unicode(name)
def return_value(search_path): init_path = self.py__file__() if os.path.basename(init_path) == '__init__.py': with open(init_path, 'rb') as f: content = common.source_to_unicode(f.read()) # these are strings that need to be used for namespace packages, # the first one is ``pkgutil``, the second ``pkg_resources``. options = ('declare_namespace(__name__)', 'extend_path(__path__') if options[0] in content or options[1] in content: # It is a namespace, now try to find the rest of the # modules on sys_path or whatever the search_path is. paths = set() for s in search_path: other = os.path.join(s, unicode(self.name)) if os.path.isdir(other): paths.add(other) return list(paths) # Default to this. return [path]
def collect_file_tests(lines, lines_to_execute): makecase = lambda t: IntegrationTestCase(t, correct, line_nr, column, start, line) start = None correct = None test_type = None for line_nr, line in enumerate(lines): line_nr += 1 # py2.5 doesn't know about the additional enumerate param if not is_py3k: line = unicode(line, 'UTF-8') if correct: r = re.match('^(\d+)\s*(.*)$', correct) if r: column = int(r.group(1)) correct = r.group(2) start += r.regs[2][0] # second group, start index else: column = len(line) - 1 # -1 for the \n if test_type == '!': yield makecase(TEST_ASSIGNMENTS) elif test_type == '<': yield makecase(TEST_USAGES) elif correct.startswith('['): yield makecase(TEST_COMPLETIONS) else: yield makecase(TEST_DEFINITIONS) correct = None else: try: r = re.search(r'(?:^|(?<=\s))#([?!<])\s*([^\n]+)', line) # test_type is ? for completion and ! for goto_assignments test_type = r.group(1) correct = r.group(2) start = r.start() except AttributeError: correct = None else: # skip the test, if this is not specified test if lines_to_execute and line_nr not in lines_to_execute: correct = None
def _path(self): """The path to a module/class/function definition.""" path = [] par = self._definition while par is not None: if isinstance(par, tree.Import): path += imports.ImportWrapper(self._evaluator, self._name).import_path break try: name = par.name except AttributeError: pass else: if isinstance(par, er.ModuleWrapper): # TODO just make the path dotted from the beginning, we id:240 gh:241 # shouldn't really split here. path[0:0] = par.py__name__().split('.') break else: path.insert(0, unicode(name)) par = par.parent return path