Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions src/debugpy/_vendored/pydevd/pydevd_file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,17 +966,14 @@ def get_abs_path_real_path_and_base_from_frame(frame, NORM_PATHS_AND_BASE_CONTAI


def get_fullname(mod_name):
import pkgutil

try:
loader = pkgutil.get_loader(mod_name)
except:
return None
if loader is not None:
for attr in ("get_filename", "_get_filename"):
meth = getattr(loader, attr, None)
if meth is not None:
return meth(mod_name)
import importlib.util

spec = importlib.util.find_spec(mod_name)
if spec is not None and spec.origin is not None and spec.has_location:
return spec.origin
except (ImportError, ModuleNotFoundError, ValueError):
pass
return None


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,3 +560,34 @@ def test_mapping_conflict_to_server():
{"remoteRoot": "/var/home/p3", "localRoot": "/opt/v2/path"},
{"remoteRoot": "/var/home/p4", "localRoot": "/opt/v2/pathsomething"},
]


def test_get_fullname(tmp_path):
"""Test that get_fullname correctly resolves module names to file paths.

This is a regression test for the fix that replaced pkgutil.get_loader
(removed in Python 3.14) with importlib.util.find_spec.
"""
from pydevd_file_utils import get_fullname

# Create a temporary module file
mod_file = tmp_path / "my_test_mod.py"
mod_file.write_text("x = 1\n")

# Add tmp_path to sys.path so the module can be found
sys.path.insert(0, str(tmp_path))
try:
result = get_fullname("my_test_mod")
assert result is not None
assert result.endswith("my_test_mod.py")

# Non-existent module should return None
result = get_fullname("nonexistent_module_xyz_12345")
assert result is None

# A stdlib package with __init__.py should be found
result = get_fullname("json")
assert result is not None
assert result.endswith("__init__.py")
finally:
sys.path.remove(str(tmp_path))
Loading