8
8
import errno
9
9
import json
10
10
import os
11
+ import platform
11
12
import shutil
12
13
import stat
13
14
import sys
19
20
from traitlets import Unicode
20
21
from traitlets .config import Application
21
22
22
- try :
23
- from .debugger import _is_debugpy_available
24
- except ImportError :
25
- _is_debugpy_available = False
26
-
27
23
pjoin = os .path .join
28
24
29
25
KERNEL_NAME = "python%i" % sys .version_info [0 ]
@@ -36,6 +32,7 @@ def make_ipkernel_cmd(
36
32
mod : str = "ipykernel_launcher" ,
37
33
executable : str | None = None ,
38
34
extra_arguments : list [str ] | None = None ,
35
+ python_arguments : list [str ] | None = None ,
39
36
) -> list [str ]:
40
37
"""Build Popen command list for launching an IPython kernel.
41
38
@@ -55,16 +52,18 @@ def make_ipkernel_cmd(
55
52
if executable is None :
56
53
executable = sys .executable
57
54
extra_arguments = extra_arguments or []
58
- arguments = [executable , "-m" , mod , "-f" , "{connection_file}" ]
59
- arguments .extend (extra_arguments )
60
-
61
- return arguments
55
+ python_arguments = python_arguments or []
56
+ return [executable , * python_arguments , "-m" , mod , "-f" , "{connection_file}" , * extra_arguments ]
62
57
63
58
64
- def get_kernel_dict (extra_arguments : list [str ] | None = None ) -> dict [str , Any ]:
59
+ def get_kernel_dict (
60
+ extra_arguments : list [str ] | None = None , python_arguments : list [str ] | None = None
61
+ ) -> dict [str , Any ]:
65
62
"""Construct dict for kernel.json"""
66
63
return {
67
- "argv" : make_ipkernel_cmd (extra_arguments = extra_arguments ),
64
+ "argv" : make_ipkernel_cmd (
65
+ extra_arguments = extra_arguments , python_arguments = python_arguments
66
+ ),
68
67
"display_name" : "Python %i (ipykernel)" % sys .version_info [0 ],
69
68
"language" : "python" ,
70
69
"metadata" : {"debugger" : True },
@@ -75,6 +74,7 @@ def write_kernel_spec(
75
74
path : Path | str | None = None ,
76
75
overrides : dict [str , Any ] | None = None ,
77
76
extra_arguments : list [str ] | None = None ,
77
+ python_arguments : list [str ] | None = None ,
78
78
) -> str :
79
79
"""Write a kernel spec directory to `path`
80
80
@@ -95,7 +95,7 @@ def write_kernel_spec(
95
95
Path (path ).chmod (mask | stat .S_IWUSR )
96
96
97
97
# write kernel.json
98
- kernel_dict = get_kernel_dict (extra_arguments )
98
+ kernel_dict = get_kernel_dict (extra_arguments , python_arguments )
99
99
100
100
if overrides :
101
101
kernel_dict .update (overrides )
@@ -113,6 +113,7 @@ def install(
113
113
prefix : str | None = None ,
114
114
profile : str | None = None ,
115
115
env : dict [str , str ] | None = None ,
116
+ frozen_modules : bool = False ,
116
117
) -> str :
117
118
"""Install the IPython kernelspec for Jupyter
118
119
@@ -137,6 +138,12 @@ def install(
137
138
A dictionary of extra environment variables for the kernel.
138
139
These will be added to the current environment variables before the
139
140
kernel is started
141
+ frozen_modules : bool, optional
142
+ Whether to use frozen modules for potentially faster kernel startup.
143
+ Using frozen modules prevents debugging inside of some built-in
144
+ Python modules, such as io, abc, posixpath, ntpath, or stat.
145
+ The frozen modules are used in CPython for faster interpreter startup.
146
+ Ignored for cPython <3.11 and for other Python implementations.
140
147
141
148
Returns
142
149
-------
@@ -145,6 +152,9 @@ def install(
145
152
if kernel_spec_manager is None :
146
153
kernel_spec_manager = KernelSpecManager ()
147
154
155
+ if env is None :
156
+ env = {}
157
+
148
158
if (kernel_name != KERNEL_NAME ) and (display_name is None ):
149
159
# kernel_name is specified and display_name is not
150
160
# default display_name to kernel_name
@@ -159,9 +169,24 @@ def install(
159
169
overrides ["display_name" ] = "Python %i [profile=%s]" % (sys .version_info [0 ], profile )
160
170
else :
161
171
extra_arguments = None
172
+
173
+ python_arguments = None
174
+
175
+ # addresses the debugger warning from debugpy about frozen modules
176
+ if sys .version_info >= (3 , 11 ) and platform .python_implementation () == "CPython" :
177
+ if not frozen_modules :
178
+ # disable frozen modules
179
+ python_arguments = ["-Xfrozen_modules=off" ]
180
+ elif "PYDEVD_DISABLE_FILE_VALIDATION" not in env :
181
+ # user opted-in to have frozen modules, and we warned them about
182
+ # consequences for the - disable the debugger warning
183
+ env ["PYDEVD_DISABLE_FILE_VALIDATION" ] = "1"
184
+
162
185
if env :
163
186
overrides ["env" ] = env
164
- path = write_kernel_spec (overrides = overrides , extra_arguments = extra_arguments )
187
+ path = write_kernel_spec (
188
+ overrides = overrides , extra_arguments = extra_arguments , python_arguments = python_arguments
189
+ )
165
190
dest = kernel_spec_manager .install_kernel_spec (
166
191
path , kernel_name = kernel_name , user = user , prefix = prefix
167
192
)
@@ -236,6 +261,12 @@ def start(self) -> None:
236
261
metavar = ("ENV" , "VALUE" ),
237
262
help = "Set environment variables for the kernel." ,
238
263
)
264
+ parser .add_argument (
265
+ "--frozen_modules" ,
266
+ action = "store_true" ,
267
+ help = "Enable frozen modules for potentially faster startup."
268
+ " This has a downside of preventing the debugger from navigating to certain built-in modules." ,
269
+ )
239
270
opts = parser .parse_args (self .argv )
240
271
if opts .env :
241
272
opts .env = dict (opts .env )
0 commit comments