__main__.py 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. # Copyright (c) Microsoft Corporation. All rights reserved.
  2. # Licensed under the MIT License. See LICENSE in the project root
  3. # for license information.
  4. __all__ = ["main"]
  5. import locale
  6. import signal
  7. import sys
  8. # WARNING: debugpy and submodules must not be imported on top level in this module,
  9. # and should be imported locally inside main() instead.
  10. def main():
  11. from debugpy import launcher
  12. from debugpy.common import log, sockets
  13. from debugpy.launcher import debuggee
  14. log.to_file(prefix="debugpy.launcher")
  15. log.describe_environment("debugpy.launcher startup environment:")
  16. if sys.platform == "win32":
  17. # For windows, disable exceptions on Ctrl+C - we want to allow the debuggee
  18. # process to handle these, or not, as it sees fit. If the debuggee exits
  19. # on Ctrl+C, the launcher will also exit, so it doesn't need to observe
  20. # the signal directly.
  21. signal.signal(signal.SIGINT, signal.SIG_IGN)
  22. # Everything before "--" is command line arguments for the launcher itself,
  23. # and everything after "--" is command line arguments for the debuggee.
  24. log.info("sys.argv before parsing: {0}", sys.argv)
  25. sep = sys.argv.index("--")
  26. launcher_argv = sys.argv[1:sep]
  27. sys.argv[:] = [sys.argv[0]] + sys.argv[sep + 1 :]
  28. log.info("sys.argv after patching: {0}", sys.argv)
  29. # The first argument specifies the host/port on which the adapter is waiting
  30. # for launcher to connect. It's either host:port, or just port.
  31. adapter = launcher_argv[0]
  32. host, sep, port = adapter.rpartition(":")
  33. host.strip("[]")
  34. if not sep:
  35. host = sockets.get_default_localhost()
  36. port = adapter
  37. port = int(port)
  38. launcher.connect(host, port)
  39. launcher.channel.wait()
  40. if debuggee.process is not None:
  41. sys.exit(debuggee.process.returncode)
  42. if __name__ == "__main__":
  43. # debugpy can also be invoked directly rather than via -m. In this case, the first
  44. # entry on sys.path is the one added automatically by Python for the directory
  45. # containing this file. This means that import debugpy will not work, since we need
  46. # the parent directory of debugpy/ to be in sys.path, rather than debugpy/launcher/.
  47. #
  48. # The other issue is that many other absolute imports will break, because they
  49. # will be resolved relative to debugpy/launcher/ - e.g. `import state` will then try
  50. # to import debugpy/launcher/state.py.
  51. #
  52. # To fix both, we need to replace the automatically added entry such that it points
  53. # at parent directory of debugpy/ instead of debugpy/launcher, import debugpy with that
  54. # in sys.path, and then remove the first entry entry altogether, so that it doesn't
  55. # affect any further imports we might do. For example, suppose the user did:
  56. #
  57. # python /foo/bar/debugpy/launcher ...
  58. #
  59. # At the beginning of this script, sys.path will contain "/foo/bar/debugpy/launcher"
  60. # as the first entry. What we want is to replace it with "/foo/bar', then import
  61. # debugpy with that in effect, and then remove the replaced entry before any more
  62. # code runs. The imported debugpy module will remain in sys.modules, and thus all
  63. # future imports of it or its submodules will resolve accordingly.
  64. if "debugpy" not in sys.modules:
  65. # Do not use dirname() to walk up - this can be a relative path, e.g. ".".
  66. sys.path[0] = sys.path[0] + "/../../"
  67. __import__("debugpy")
  68. del sys.path[0]
  69. # Apply OS-global and user-specific locale settings.
  70. try:
  71. locale.setlocale(locale.LC_ALL, "")
  72. except Exception:
  73. # On POSIX, locale is set via environment variables, and this can fail if
  74. # those variables reference a non-existing locale. Ignore and continue using
  75. # the default "C" locale if so.
  76. pass
  77. main()