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