diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 0e9d140c..ab6b315e 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -34,9 +34,7 @@ def _get_signature_param_names(signatures, positional_count, used_kwargs): # Add named params for call_sig in signatures: for i, p in enumerate(call_sig.params): - # Allow protected access, because it's a public API. - # TODO reconsider with Python 2 drop - kind = p._name.get_kind() + kind = p.kind if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD: continue if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \ @@ -51,8 +49,7 @@ def _must_be_kwarg(signatures, positional_count, used_kwargs): must_be_kwarg = True for signature in signatures: for i, p in enumerate(signature.params): - # TODO reconsider with Python 2 drop - kind = p._name.get_kind() + kind = p.kind if kind is Parameter.VAR_POSITIONAL: # In case there were not already kwargs, the next param can # always be a normal argument. diff --git a/jedi/api/environment.py b/jedi/api/environment.py index a9c1e227..79fac4f9 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -257,7 +257,7 @@ def _get_cached_default_environment(): return InterpreterEnvironment() -def find_virtualenvs(paths=None, **kwargs): +def find_virtualenvs(paths=None, *, safe=True, use_environment_vars=True): """ :param paths: A list of paths in your file system to be scanned for Virtualenvs. It will search in these paths and potentially execute the @@ -274,47 +274,44 @@ def find_virtualenvs(paths=None, **kwargs): :yields: :class:`.Environment` """ - def py27_comp(paths=None, safe=True, use_environment_vars=True): - if paths is None: - paths = [] + if paths is None: + paths = [] - _used_paths = set() + _used_paths = set() - if use_environment_vars: - # Using this variable should be safe, because attackers might be - # able to drop files (via git) but not environment variables. - virtual_env = _get_virtual_env_from_var() - if virtual_env is not None: - yield virtual_env - _used_paths.add(virtual_env.path) + if use_environment_vars: + # Using this variable should be safe, because attackers might be + # able to drop files (via git) but not environment variables. + virtual_env = _get_virtual_env_from_var() + if virtual_env is not None: + yield virtual_env + _used_paths.add(virtual_env.path) - conda_env = _get_virtual_env_from_var(_CONDA_VAR) - if conda_env is not None: - yield conda_env - _used_paths.add(conda_env.path) + conda_env = _get_virtual_env_from_var(_CONDA_VAR) + if conda_env is not None: + yield conda_env + _used_paths.add(conda_env.path) - for directory in paths: - if not os.path.isdir(directory): + for directory in paths: + if not os.path.isdir(directory): + continue + + directory = os.path.abspath(directory) + for path in os.listdir(directory): + path = os.path.join(directory, path) + if path in _used_paths: + # A path shouldn't be inferred twice. continue + _used_paths.add(path) - directory = os.path.abspath(directory) - for path in os.listdir(directory): - path = os.path.join(directory, path) - if path in _used_paths: - # A path shouldn't be inferred twice. - continue - _used_paths.add(path) - - try: - executable = _get_executable_path(path, safe=safe) - yield Environment(executable) - except InvalidPythonEnvironment: - pass - - return py27_comp(paths, **kwargs) + try: + executable = _get_executable_path(path, safe=safe) + yield Environment(executable) + except InvalidPythonEnvironment: + pass -def find_system_environments(**kwargs): +def find_system_environments(*, env_vars={}): """ Ignores virtualenvs and returns the Python versions that were installed on your system. This might return nothing, if you're running Python e.g. from @@ -326,14 +323,14 @@ def find_system_environments(**kwargs): """ for version_string in _SUPPORTED_PYTHONS: try: - yield get_system_environment(version_string, **kwargs) + yield get_system_environment(version_string, env_vars=env_vars) except InvalidPythonEnvironment: pass # TODO: this function should probably return a list of environments since # multiple Python installations can be found on a system for the same version. -def get_system_environment(version, **kwargs): +def get_system_environment(version, *, env_vars={}): """ Return the first Python environment found for a string of the form 'X.Y' where X and Y are the major and minor versions of Python. @@ -350,26 +347,20 @@ def get_system_environment(version, **kwargs): if os.name == 'nt': for exe in _get_executables_from_windows_registry(version): try: - return Environment(exe, **kwargs) + return Environment(exe, env_vars=env_vars) except InvalidPythonEnvironment: pass raise InvalidPythonEnvironment("Cannot find executable python%s." % version) -def create_environment(path, safe=True, **kwargs): +def create_environment(path, *, safe=True, env_vars={}): """ Make it possible to manually create an Environment object by specifying a Virtualenv path or an executable path and optional environment variables. :raises: :exc:`.InvalidPythonEnvironment` :returns: :class:`.Environment` - - TODO: make env_vars a kwarg when Python 2 is dropped. For now, preserve API """ - return _create_environment(path, safe, **kwargs) - - -def _create_environment(path, safe=True, env_vars={}): if os.path.isfile(path): _assert_safe(path, safe) return Environment(path, env_vars=env_vars) @@ -393,11 +384,7 @@ def _get_executable_path(path, safe=True): def _get_executables_from_windows_registry(version): - # The winreg module is named _winreg on Python 2. - try: - import winreg - except ImportError: - import _winreg as winreg + import winreg # TODO: support Python Anaconda. sub_keys = [ diff --git a/jedi/api/helpers.py b/jedi/api/helpers.py index f9e7d8b6..2198e196 100644 --- a/jedi/api/helpers.py +++ b/jedi/api/helpers.py @@ -295,8 +295,7 @@ def _iter_arguments(nodes, position): # Returns Generator[Tuple[star_count, Optional[key_start: str], had_equal]] nodes_before = [c for c in nodes if c.start_pos < position] if nodes_before[-1].type == 'arglist': - for x in _iter_arguments(nodes_before[-1].children, position): - yield x # Python 2 :( + yield from _iter_arguments(nodes_before[-1].children, position) return previous_node_yielded = False @@ -321,7 +320,7 @@ def _iter_arguments(nodes, position): else: yield 0, None, False stars_seen = 0 - elif node.type in ('testlist', 'testlist_star_expr'): # testlist is Python 2 + elif node.type == 'testlist_star_expr': for n in node.children[::2]: if n.type == 'star_expr': stars_seen = 1 diff --git a/jedi/api/project.py b/jedi/api/project.py index 472507f2..0ba79e17 100644 --- a/jedi/api/project.py +++ b/jedi/api/project.py @@ -211,7 +211,7 @@ class Project(object): self._environment = get_cached_default_environment() return self._environment - def search(self, string, **kwargs): + def search(self, string, *, all_scopes=False): """ Searches a name in the whole project. If the project is very big, at some point Jedi will stop searching. However it's also very much @@ -232,7 +232,7 @@ class Project(object): functions and classes. :yields: :class:`.Name` """ - return self._search(string, **kwargs) + return self._search_func(string, all_scopes=all_scopes) def complete_search(self, string, **kwargs): """ @@ -246,9 +246,6 @@ class Project(object): """ return self._search_func(string, complete=True, **kwargs) - def _search(self, string, all_scopes=False): # Python 2.. - return self._search_func(string, all_scopes=all_scopes) - @_try_to_skip_duplicates def _search_func(self, string, complete=False, all_scopes=False): # Using a Script is they easiest way to get an empty module context. @@ -290,7 +287,7 @@ class Project(object): continue debug.dbg('Search of a specific module %s', m) - for x in search_in_module( + yield from search_in_module( inference_state, m, names=[m.name], @@ -299,15 +296,14 @@ class Project(object): complete=complete, convert=True, ignore_imports=True, - ): - yield x # Python 2... + ) # 2. Search for identifiers in the project. for module_context in search_in_file_ios(inference_state, file_ios, name): names = get_module_names(module_context.tree_node, all_scopes=all_scopes) names = [module_context.create_name(n) for n in names] names = _remove_imports(names) - for x in search_in_module( + yield from search_in_module( inference_state, module_context, names=names, @@ -315,8 +311,7 @@ class Project(object): wanted_names=wanted_names, complete=complete, ignore_imports=True, - ): - yield x # Python 2... + ) # 3. Search for modules on sys.path sys_path = [ @@ -326,7 +321,7 @@ class Project(object): if not p.startswith(self._path) ] names = list(iter_module_names(inference_state, empty_module_context, sys_path)) - for x in search_in_module( + yield from search_in_module( inference_state, empty_module_context, names=names, @@ -334,8 +329,7 @@ class Project(object): wanted_names=wanted_names, complete=complete, convert=True, - ): - yield x # Python 2... + ) def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self._path) diff --git a/jedi/api/refactoring/extract.py b/jedi/api/refactoring/extract.py index ad2ded9c..6e7df7e1 100644 --- a/jedi/api/refactoring/extract.py +++ b/jedi/api/refactoring/extract.py @@ -350,8 +350,7 @@ def _find_non_global_names(nodes): if node.type == 'trailer' and node.children[0] == '.': continue - for x in _find_non_global_names(children): # Python 2... - yield x + yield from _find_non_global_names(children) def _get_code_insertion_node(node, is_bound_method): diff --git a/jedi/debug.py b/jedi/debug.py index 80673cce..898b640a 100644 --- a/jedi/debug.py +++ b/jedi/debug.py @@ -97,10 +97,8 @@ def increase_indent_cm(title=None, color='MAGENTA'): dbg('End: ' + title, color=color) -def dbg(message, *args, **kwargs): +def dbg(message, *args, color='GREEN'): """ Looks at the stack, to see if a debug message should be printed. """ - # Python 2 compatibility, because it doesn't understand default args - color = kwargs.pop('color', 'GREEN') assert color if debug_function and enable_notice: