diff --git a/CONFIGURATION.md b/CONFIGURATION.md index bb07fce9..0609169b 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -21,6 +21,7 @@ This server can be configured using the `workspace/didChangeConfiguration` metho | `pylsp.plugins.flake8.select` | `array` of unique `string` items | List of errors and warnings to enable. | `null` | | `pylsp.plugins.jedi.auto_import_modules` | `array` of `string` items | List of module names for jedi.settings.auto_import_modules. | `["numpy"]` | | `pylsp.plugins.jedi.extra_paths` | `array` of `string` items | Define extra paths for jedi.Script. | `[]` | +| `pylsp.plugins.jedi.prioritize_extra_paths` | `boolean` | Whether to place extra_paths at the beginning (true) or end (false) of `sys.path` | `false` | | `pylsp.plugins.jedi.env_vars` | `object` | Define environment variables for jedi.Script and Jedi.names. | `null` | | `pylsp.plugins.jedi.environment` | `string` | Define environment for jedi.Script and Jedi.names. | `null` | | `pylsp.plugins.jedi_completion.enabled` | `boolean` | Enable or disable the plugin. | `true` | diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json index 2259f1cc..18248384 100644 --- a/pylsp/config/schema.json +++ b/pylsp/config/schema.json @@ -151,6 +151,11 @@ }, "description": "Define extra paths for jedi.Script." }, + "pylsp.plugins.jedi.prioritize_extra_paths": { + "type": "boolean", + "default": false, + "description": "Whether to place extra_paths at the beginning (true) or end (false) of `sys.path`" + }, "pylsp.plugins.jedi.env_vars": { "type": [ "object", diff --git a/pylsp/workspace.py b/pylsp/workspace.py index 139028cc..23e815bb 100644 --- a/pylsp/workspace.py +++ b/pylsp/workspace.py @@ -521,6 +521,7 @@ def jedi_script(self, position=None, use_document_path=False): extra_paths = [] environment_path = None env_vars = None + prioritize_extra_paths = False if self._config: jedi_settings = self._config.plugin_settings( @@ -537,19 +538,19 @@ def jedi_script(self, position=None, use_document_path=False): extra_paths = jedi_settings.get("extra_paths") or [] env_vars = jedi_settings.get("env_vars") + prioritize_extra_paths = jedi_settings.get("prioritize_extra_paths") - # Drop PYTHONPATH from env_vars before creating the environment because that makes - # Jedi throw an error. + # Drop PYTHONPATH from env_vars before creating the environment to + # ensure that Jedi can startup properly without module name collision. if env_vars is None: env_vars = os.environ.copy() env_vars.pop("PYTHONPATH", None) - environment = ( - self.get_enviroment(environment_path, env_vars=env_vars) - if environment_path - else None + environment = self.get_enviroment(environment_path, env_vars=env_vars) + sys_path = self.sys_path( + environment_path, env_vars, prioritize_extra_paths, extra_paths ) - sys_path = self.sys_path(environment_path, env_vars=env_vars) + extra_paths + project_path = self._workspace.root_path # Extend sys_path with document's path if requested @@ -559,7 +560,7 @@ def jedi_script(self, position=None, use_document_path=False): kwargs = { "code": self.source, "path": self.path, - "environment": environment, + "environment": environment if environment_path else None, "project": jedi.Project(path=project_path, sys_path=sys_path), } @@ -584,14 +585,24 @@ def get_enviroment(self, environment_path=None, env_vars=None): return environment - def sys_path(self, environment_path=None, env_vars=None): + def sys_path( + self, + environment_path=None, + env_vars=None, + prioritize_extra_paths=False, + extra_paths=[], + ): # Copy our extra sys path - # TODO: when safe to break API, use env_vars explicitly to pass to create_environment path = list(self._extra_sys_path) environment = self.get_enviroment( environment_path=environment_path, env_vars=env_vars ) path.extend(environment.get_sys_path()) + if prioritize_extra_paths: + path += extra_paths + path + else: + path += path + extra_paths + return path