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
5from __future__ import absolute_import, division, print_function, unicode_literals
6
7"""An implementation of the Debug Adapter Protocol (DAP) for Python.
8
9https://microsoft.github.io/debug-adapter-protocol/
10"""
11
12# debugpy stable public API consists solely of members of this module that are
13# enumerated below.
14__all__ = [
15    "__version__",
16    "breakpoint",
17    "configure",
18    "connect",
19    "debug_this_thread",
20    "is_client_connected",
21    "listen",
22    "log_to",
23    "trace_this_thread",
24    "wait_for_client",
25]
26
27import codecs
28import os
29
30from debugpy import _version
31from debugpy.common import compat
32
33
34# Expose debugpy.server API from subpackage, but do not actually import it unless
35# and until a member is invoked - we don't want the server package loaded in the
36# adapter, the tests, or setup.py.
37
38# Docstrings for public API members must be formatted according to PEP 8 - no more
39# than 72 characters per line! - and must be readable when retrieved via help().
40
41
42def log_to(path):
43    """Generate detailed debugpy logs in the specified directory.
44
45    The directory must already exist. Several log files are generated,
46    one for every process involved in the debug session.
47    """
48
49    from debugpy.server import api
50
51    return api.log_to(path)
52
53
54def configure(properties=None, **kwargs):
55    """Sets debug configuration properties that cannot be set in the
56    "attach" request, because they must be applied as early as possible
57    in the process being debugged.
58
59    For example, a "launch" configuration with subprocess debugging
60    disabled can be defined entirely in JSON::
61
62        {
63            "request": "launch",
64            "subProcess": false,
65            ...
66        }
67
68    But the same cannot be done with "attach", because "subProcess"
69    must be known at the point debugpy starts tracing execution. Thus,
70    it is not available in JSON, and must be omitted::
71
72        {
73            "request": "attach",
74            ...
75        }
76
77    and set from within the debugged process instead::
78
79        debugpy.configure(subProcess=False)
80        debugpy.listen(...)
81
82    Properties to set can be passed either as a single dict argument,
83    or as separate keyword arguments::
84
85        debugpy.configure({"subProcess": False})
86    """
87
88    from debugpy.server import api
89
90    return api.configure(properties, **kwargs)
91
92
93def listen(address):
94    """Starts a debug adapter debugging this process, that listens for
95    incoming socket connections from clients on the specified address.
96
97    address must be either a (host, port) tuple, as defined by the
98    standard socket module for the AF_INET address family, or a port
99    number. If only the port is specified, host is "127.0.0.1".
100
101    Returns the interface and the port on which the debug adapter is
102    actually listening, in the same format as address. This may be
103    different from address if port was 0 in the latter, in which case
104    the adapter will pick some unused ephemeral port to listen on.
105
106    This function does't wait for a client to connect to the debug
107    adapter that it starts. Use wait_for_client() to block execution
108    until the client connects.
109    """
110
111    from debugpy.server import api
112
113    return api.listen(address)
114
115
116@compat.kwonly
117def connect(address, access_token=None):
118    """Tells an existing debug adapter instance that is listening on the
119    specified address to debug this process.
120
121    address must be either a (host, port) tuple, as defined by the
122    standard socket module for the AF_INET address family, or a port
123    number. If only the port is specified, host is "127.0.0.1".
124
125    access_token must be the same value that was passed to the adapter
126    via the --server-access-token command-line switch.
127
128    This function does't wait for a client to connect to the debug
129    adapter that it connects to. Use wait_for_client() to block
130    execution until the client connects.
131    """
132
133    from debugpy.server import api
134
135    return api.connect(address, access_token=access_token)
136
137
138def wait_for_client():
139    """If there is a client connected to the debug adapter that is
140    debugging this process, returns immediately. Otherwise, blocks
141    until a client connects to the adapter.
142
143    While this function is waiting, it can be canceled by calling
144    wait_for_client.cancel() from another thread.
145    """
146
147    from debugpy.server import api
148
149    return api.wait_for_client()
150
151
152def is_client_connected():
153    """True if a client is connected to the debug adapter that is
154    debugging this process.
155    """
156
157    from debugpy.server import api
158
159    return api.is_client_connected()
160
161
162def breakpoint():
163    """If a client is connected to the debug adapter that is debugging
164    this process, pauses execution of all threads, and simulates a
165    breakpoint being hit at the line following the call.
166
167    On Python 3.7 and above, this is the same as builtins.breakpoint().
168    """
169
170    from debugpy.server import api
171
172    return api.breakpoint()
173
174
175def debug_this_thread():
176    """Makes the debugger aware of the current thread.
177
178    Must be called on any background thread that is started by means
179    other than the usual Python APIs (i.e. the "threading" module),
180    in order for breakpoints to work on that thread.
181    """
182
183    from debugpy.server import api
184
185    return api.debug_this_thread()
186
187
188def trace_this_thread(should_trace):
189    """Tells the debug adapter to enable or disable tracing on the
190    current thread.
191
192    When the thread is traced, the debug adapter can detect breakpoints
193    being hit, but execution is slower, especially in functions that
194    have any breakpoints set in them. Disabling tracing when breakpoints
195    are not anticipated to be hit can improve performance. It can also
196    be used to skip breakpoints on a particular thread.
197
198    Tracing is automatically disabled for all threads when there is no
199    client connected to the debug adapter.
200    """
201
202    from debugpy.server import api
203
204    return api.trace_this_thread(should_trace)
205
206
207__version__ = _version.get_versions()["version"]
208
209# Force absolute path on Python 2.
210__file__ = os.path.abspath(__file__)
211
212# Preload encodings that we're going to use to avoid import deadlocks on Python 2,
213# before importing anything from debugpy.
214map(codecs.lookup, ["ascii", "utf8", "utf-8", "latin1", "latin-1", "idna", "hex"])
215