diff --git a/src/debugpy/_vendored/__init__.py b/src/debugpy/_vendored/__init__.py index 0d6376ae6..abde2e333 100644 --- a/src/debugpy/_vendored/__init__.py +++ b/src/debugpy/_vendored/__init__.py @@ -15,16 +15,14 @@ VENDORED_ROOT = os.path.dirname(os.path.abspath(__file__)) # TODO: Move the "pydevd" git submodule to the debugpy/_vendored directory # and then drop the following fallback. -if 'pydevd' not in os.listdir(VENDORED_ROOT): +if "pydevd" not in os.listdir(VENDORED_ROOT): VENDORED_ROOT = os.path.dirname(VENDORED_ROOT) def list_all(resolve=False): """Return the list of vendored projects.""" # TODO: Derive from os.listdir(VENDORED_ROOT)? - projects = [ - 'pydevd', - ] + projects = ["pydevd"] if not resolve: return projects return [project_root(name) for name in projects] @@ -37,7 +35,7 @@ def project_root(project): projects (e.g. "debugpy/_vendored/") will be returned. """ if not project: - project = '' + project = "" return os.path.join(VENDORED_ROOT, project) @@ -63,17 +61,14 @@ def iter_packaging_files(project): prune_dir = None exclude_file = None try: - mod = import_module('._{}_packaging'.format(project), __name__) + mod = import_module("._{}_packaging".format(project), __name__) except ImportError: pass else: - prune_dir = getattr(mod, 'prune_dir', prune_dir) - exclude_file = getattr(mod, 'exclude_file', exclude_file) + prune_dir = getattr(mod, "prune_dir", prune_dir) + exclude_file = getattr(mod, "exclude_file", exclude_file) results = iter_project_files( - project, - relative=True, - prune_dir=prune_dir, - exclude_file=exclude_file, + project, relative=True, prune_dir=prune_dir, exclude_file=exclude_file ) for _, _, filename in results: yield filename @@ -89,6 +84,7 @@ def match(name, module): return True else: return False + return match @@ -101,10 +97,14 @@ def check_modules(project, match, root=None): for modname, mod in list(sys.modules.items()): if not match(modname, mod): continue - if not hasattr(mod, '__file__'): # extension module + try: + filename = getattr(mod, "__file__", None) + except: # In theory it's possible that any error is raised when accessing __file__ + filename = None + if not filename: # extension module extensions.append(modname) - elif not mod.__file__.startswith(root): - unvendored[modname] = mod.__file__ + elif not filename.startswith(root): + unvendored[modname] = filename return unvendored, extensions diff --git a/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_imports_tipper.py b/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_imports_tipper.py index 510fc820d..7ba858d98 100644 --- a/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_imports_tipper.py +++ b/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_imports_tipper.py @@ -86,12 +86,14 @@ def get_file(mod): try: f = inspect.getsourcefile(mod) or inspect.getfile(mod) except: - if hasattr_checked(mod, '__file__'): - f = mod.__file__ - if f.lower(f[-4:]) in ['.pyc', '.pyo']: - filename = f[:-4] + '.py' - if os.path.exists(filename): - f = filename + try: + f = getattr(mod, '__file__', None) + except: + f = None + if f and f.lower(f[-4:]) in ['.pyc', '.pyo']: + filename = f[:-4] + '.py' + if os.path.exists(filename): + f = filename return f diff --git a/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_jy_imports_tipper.py b/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_jy_imports_tipper.py index 28d5f6b19..558d5632e 100644 --- a/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_jy_imports_tipper.py +++ b/src/debugpy/_vendored/pydevd/_pydev_bundle/_pydev_jy_imports_tipper.py @@ -56,8 +56,10 @@ def Find(name): parent = mod foundAs = '' - if hasattr(mod, '__file__'): - f = mod.__file__ + try: + f = getattr(mod, '__file__', None) + except: + f = None components = name.split('.') diff --git a/src/debugpy/_vendored/pydevd/stubs/_get_tips.py b/src/debugpy/_vendored/pydevd/stubs/_get_tips.py index b98e1c536..79dffaaa0 100644 --- a/src/debugpy/_vendored/pydevd/stubs/_get_tips.py +++ b/src/debugpy/_vendored/pydevd/stubs/_get_tips.py @@ -62,9 +62,12 @@ def GetFile(mod): try: f = inspect.getsourcefile(mod) or inspect.getfile(mod) except: - if hasattr(mod, '__file__'): - f = mod.__file__ - if f.lower(f[-4:]) in ['.pyc', '.pyo']: + try: + f = getattr(mod, '__file__', None) + except: + pass + else: + if f and f.lower(f[-4:]) in ['.pyc', '.pyo']: filename = f[:-4] + '.py' if os.path.exists(filename): f = filename diff --git a/tests/tests/test_vendoring.py b/tests/tests/test_vendoring.py new file mode 100644 index 000000000..dd6c4269b --- /dev/null +++ b/tests/tests/test_vendoring.py @@ -0,0 +1,34 @@ +def test_vendoring(pyfile): + @pyfile + def import_debugpy(): + import sys + + class Dummy(object): + __file__ = None + + class Dummy2(object): + pass + + class Dummy3(object): + def __getattribute__(self, *args, **kwargs): + raise AssertionError('Error') + + sys.modules["pydev_dummy"] = Dummy() + sys.modules["pydev_dummy2"] = Dummy2() + sys.modules["pydev_dummy3"] = Dummy3() + + sys.modules["_pydev_dummy"] = Dummy() + sys.modules["_pydev_dummy2"] = Dummy2() + sys.modules["_pydev_dummy3"] = Dummy3() + + from debugpy._vendored import force_pydevd # noqa + + print("Properly applied pydevd vendoring.") + + import subprocess + import sys + + output = subprocess.check_output([sys.executable, "-u", import_debugpy.strpath]) + output = output.decode("utf-8") + if "Properly applied pydevd vendoring." not in output: + raise AssertionError(output)