diff --git a/setup.py b/setup.py index 1bfba237b..d16a27c5c 100644 --- a/setup.py +++ b/setup.py @@ -195,5 +195,7 @@ def tail_is(*suffixes): ext_modules=ExtModules(), has_ext_modules=lambda: True, cmdclass=cmds, + # allow the user to call "debugpy" instead of "python -m debugpy" + entry_points={"console_scripts": ["debugpy = debugpy.server.cli:main"]}, **extras ) diff --git a/src/debugpy/__main__.py b/src/debugpy/__main__.py index 24c2b7faa..14b9013c5 100644 --- a/src/debugpy/__main__.py +++ b/src/debugpy/__main__.py @@ -4,34 +4,66 @@ import sys - if __name__ == "__main__": - # debugpy can also be invoked directly rather than via -m. In this case, the first - # entry on sys.path is the one added automatically by Python for the directory - # containing this file. This means that import debugpy will not work, since we need - # the parent directory of debugpy/ to be in sys.path, rather than debugpy/ itself. + + # There are three ways to run debugpy: + # + # 1. Installed as a module in the current environment (python -m debugpy ...) + # 2. Run as a script from source code (python /src/debugpy ...) + # 3. Installed as a module in a random directory + # + # ----- + # + # In the first case, no extra work is needed. Importing debugpy will work as expected. + # Also, running 'debugpy' instead of 'python -m debugpy' will work because of the entry point + # defined in setup.py. + # + # ----- + # + # In the second case, sys.path[0] is the one added automatically by Python for the directory + # containing this file. 'import debugpy' will not work since we need the parent directory + # of debugpy/ to be in sys.path, rather than debugpy/ itself. So we need to modify sys.path[0]. + # Running 'debugpy' will not work because the entry point is not defined in this case. # - # The other issue is that many other absolute imports will break, because they - # will be resolved relative to debugpy/ - e.g. `import debugger` will then try + # ----- + # + # In the third case, running 'python -m debugpy' will not work because the module is not installed + # in any environment. Running 'python /debugpy' will work, just like the second case. + # But running the entry point will not work because python doesn't know where to find the debugpy module. + # + # In this case, no changes to sys.path are required. You just have to do the following before calling + # the entry point: + # 1. Add to PYTHONPATH. + # On Windows, this is set PYTHONPATH=%PYTHONPATH%; + # 2. Add /bin to PATH. (OPTIONAL) + # On Windows, this is set PATH=%PATH%;\bin + # 3. Run the entry point from a command prompt + # On Windows, this is \bin\debugpy.exe, or just 'debugpy' if you did the previous step. + # + # ----- + # + # If we modify sys.path, 'import debugpy' will work, but it will break other imports + # because they will be resolved relative to debugpy/ - e.g. `import debugger` will try # to import debugpy/debugger.py. # - # To fix both, we need to replace the automatically added entry such that it points - # at parent directory of debugpy/ instead of debugpy/ itself, import debugpy with that - # in sys.path, and then remove the first entry entry altogether, so that it doesn't - # affect any further imports we might do. For example, suppose the user did: + # To fix both problems, we need to do the following steps: + # 1. Modify sys.path[0] to point at the parent directory of debugpy/ instead of debugpy/ itself. + # 2. Import debugpy. + # 3. Remove sys.path[0] so that it doesn't affect future imports. + # + # For example, suppose the user did: # # python /foo/bar/debugpy ... # - # At the beginning of this script, sys.path will contain "/foo/bar/debugpy" as the - # first entry. What we want is to replace it with "/foo/bar', then import debugpy - # with that in effect, and then remove the replaced entry before any more - # code runs. The imported debugpy module will remain in sys.modules, and thus all - # future imports of it or its submodules will resolve accordingly. + # At the beginning of this script, sys.path[0] will contain "/foo/bar/debugpy". + # We want to replace it with "/foo/bar', then 'import debugpy', then remove the replaced entry. + # The imported debugpy module will remain in sys.modules, and thus all future imports of it + # or its submodules will resolve accordingly. if "debugpy" not in sys.modules: + # Do not use dirname() to walk up - this can be a relative path, e.g. ".". sys.path[0] = sys.path[0] + "/../" import debugpy # noqa - del sys.path[0] from debugpy.server import cli