From e4ee21862ba0b2abdfde43f583b0a709d2f9bfb9 Mon Sep 17 00:00:00 2001 From: Maxim Romanyuk Date: Thu, 9 Jul 2026 01:46:43 +0500 Subject: [PATCH] Fix crash in pylsp_definitions on definitions without a source position When follow_builtin_definitions is True (the default), the return-list comprehension filter short-circuits `follow_builtin_defns or _not_internal_definition(d)`, so the None-guards inside _not_internal_definition never run. A jedi definition that resolves into a compiled/builtin module has line/column == None, so `d.line - 1` raises `TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'`. Exclude definitions with no line/column unconditionally: they cannot form a valid LSP range regardless of the follow_builtin_definitions setting. Fixes #623 Fixes #624 Co-Authored-By: Claude Opus 4.8 (1M context) --- pylsp/plugins/definition.py | 5 ++++- test/plugins/test_definitions.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pylsp/plugins/definition.py b/pylsp/plugins/definition.py index 1ddc03a0..a40ffbbd 100644 --- a/pylsp/plugins/definition.py +++ b/pylsp/plugins/definition.py @@ -71,7 +71,10 @@ def pylsp_definitions( }, } for d in definitions - if d.is_definition() and (follow_builtin_defns or _not_internal_definition(d)) + if d.is_definition() + and d.line is not None + and d.column is not None + and (follow_builtin_defns or _not_internal_definition(d)) ] diff --git a/test/plugins/test_definitions.py b/test/plugins/test_definitions.py index 7923524b..211c4437 100644 --- a/test/plugins/test_definitions.py +++ b/test/plugins/test_definitions.py @@ -3,6 +3,8 @@ import os +import jedi + from pylsp import uris from pylsp.plugins.definition import pylsp_definitions from pylsp.workspace import Document @@ -173,3 +175,27 @@ def foo(): assert [{"uri": module_uri, "range": def_range}] == pylsp_definitions( config, doc, cursor_pos ) + + +def test_definition_without_source_position(config, workspace, monkeypatch) -> None: + # A definition jedi resolves without a source position (e.g. a compiled + # builtin, where line/column are None) must be dropped, not crash with + # `TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'`. + # Regression test for #623 and #624. + class _NoPositionName: + line = None + column = None + module_path = None + name = "compiled" + + def is_definition(self) -> bool: + return True + + monkeypatch.setattr( + jedi.api.Script, "goto", lambda *args, **kwargs: [_NoPositionName()] + ) + + doc = Document(DOC_URI, workspace, DOC) + # follow_builtin_definitions defaults to True, so the None-guard in the + # return comprehension is the only thing preventing the crash. + assert pylsp_definitions(config, doc, {"line": 3, "character": 6}) == []