1919from multilspy .multilspy_logger import MultilspyLogger
2020
2121import logging
22+ import sys
2223# Configure logging
2324logging .basicConfig (level = logging .DEBUG , format = '%(filename)s - %(asctime)s - %(levelname)s - %(message)s' )
2425
@@ -164,7 +165,29 @@ def second_pass(self, graph: Graph, files: list[Path], path: Path) -> None:
164165 else :
165166 lsps [".java" ] = NullLanguageServer ()
166167 if any (path .rglob ('*.py' )):
167- config = MultilspyConfig .from_dict ({"code_language" : "python" , "environment_path" : f"{ path } /venv" })
168+ py_venv = path / "venv"
169+ py_dotvenv = path / ".venv"
170+ if py_venv .is_dir () and (py_venv / "bin" / "python" ).exists ():
171+ env_path = str (py_venv )
172+ elif py_dotvenv .is_dir () and (py_dotvenv / "bin" / "python" ).exists ():
173+ env_path = str (py_dotvenv )
174+ else :
175+ # Fall back to the host's Python environment so jedi has a
176+ # valid interpreter to introspect; otherwise every
177+ # request_definition() raises InvalidPythonEnvironment and
178+ # we'd silently produce a graph with zero CALLS edges.
179+ # sys.prefix is the active environment root and is more
180+ # reliable than deriving it from sys.executable (which breaks
181+ # when the interpreter is a wrapper/shim).
182+ env_path = sys .prefix
183+ logging .info (
184+ "No venv at %s; falling back to host env %s for jedi LSP" ,
185+ path , env_path ,
186+ )
187+ config = MultilspyConfig .from_dict ({
188+ "code_language" : "python" ,
189+ "environment_path" : env_path ,
190+ })
168191 lsps [".py" ] = SyncLanguageServer .create (config , logger , str (path ))
169192 else :
170193 lsps [".py" ] = NullLanguageServer ()
@@ -189,6 +212,14 @@ def second_pass(self, graph: Graph, files: list[Path], path: Path) -> None:
189212 resolvable : list [Path ] = []
190213 for file_path in files :
191214 if file_path not in self .files :
215+ # first_pass skipped this file (e.g. parse error, empty,
216+ # untracked, or ignored after entering the candidate list).
217+ # Skip in second_pass too instead of crashing the whole
218+ # index.
219+ logging .warning (
220+ "second_pass: %s not in files map (first_pass skipped it); skipping" ,
221+ file_path ,
222+ )
192223 continue
193224 if isinstance (lsps .get (file_path .suffix ), NullLanguageServer ):
194225 continue
@@ -287,21 +318,26 @@ def analyze_local_folder(self, path: str, g: Graph, ignore: Optional[list[str]]
287318
288319 logging .info ("Done analyzing path" )
289320
290- def analyze_local_repository (self , path : str , ignore : Optional [list [str ]] = None ) -> Graph :
321+ def analyze_local_repository (self , path : str , ignore : Optional [list [str ]] = None , branch : Optional [ str ] = None ) -> Graph :
291322 """
292323 Analyze a local Git repository.
293324
294325 Args:
295326 path (str): Path to a local git repository
296327 ignore (List(str)): List of paths to skip
328+ branch (Optional[str]): Branch name. Auto-detected from the
329+ checkout when ``None``.
297330 """
298331 if ignore is None :
299332 ignore = []
300333
301334 from pygit2 .repository import Repository
335+ from ..project import detect_branch
302336
303337 proj_name = Path (path ).name
304- graph = Graph (proj_name )
338+ if branch is None :
339+ branch = detect_branch (Path (path ))
340+ graph = Graph (proj_name , branch = branch )
305341 self .analyze_local_folder (path , graph , ignore )
306342
307343 # Save processed commit hash to the DB
0 commit comments