src/black/handle_ipynb_magics.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | """Functions to process IPython magics with."""
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | import ast
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | import collections
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | import dataclasses
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | import secrets
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | import sys
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from functools import lru_cache
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from importlib.util import find_spec
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from typing import Dict, List, Optional, Tuple
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | if sys.version_info >= (3, 10):
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from typing import TypeGuard
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | else:
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from typing_extensions import TypeGuard
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from black.output import out
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | from black.report import NothingChanged
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | TRANSFORMED_MAGICS = frozenset((
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "get_ipython().run_cell_magic",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "get_ipython().system",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "get_ipython().getoutput",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "get_ipython().run_line_magic",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | ))
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | TOKENS_TO_IGNORE = frozenset((
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "ENDMARKER",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "NL",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "NEWLINE",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "COMMENT",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "DEDENT",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "UNIMPORTANT_WS",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "ESCAPED_NL",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | ))
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | PYTHON_CELL_MAGICS = frozenset((
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "capture",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "prun",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "pypy",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "python",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "python3",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "time",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | "timeit",
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | ))
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | TOKEN_HEX = secrets.token_hex
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | @dataclasses.dataclass(frozen=True)
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | class Replacement:
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | mask: str
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | src: str
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | @lru_cache
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | def jupyter_dependencies_are_installed(*, warn: bool) -> bool:
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | installed = (
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | find_spec("tokenize_rt") is not None and find_spec("IPython") is not None
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | )
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | if not installed and warn:
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | msg = (
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | "Skipping .ipynb files as Jupyter dependencies are not installed.\n"
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | 'You can fix this by running ``pip install "black[jupyter]"``'
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | )
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | out(msg)
0012 0007 0012 0000 0000 0000 0000 -- 04 003 008 005 009 011 014 0048.43 0081.73 0001.69 | return installed
0012 0007 0012 0000 0000 0000 0000 -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | def remove_trailing_semicolon(src: str) -> Tuple[str, bool]:
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | """Remove trailing semicolon from Jupyter notebook cell.
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | For example,
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | fig, ax = plt.subplots()
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | ax.plot(x_data, y_data); # plot data
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | would become
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | fig, ax = plt.subplots()
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | ax.plot(x_data, y_data) # plot data
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | ``tokenize_rt`` so that round-tripping works fine.
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | """
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | from tokenize_rt import reversed_enumerate, src_to_tokens, tokens_to_src
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | tokens = src_to_tokens(src)
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | trailing_semicolon = False
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | for idx, token in reversed_enumerate(tokens):
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | if token.name in TOKENS_TO_IGNORE:
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | continue
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | if token.name == "OP" and token.src == ";":
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | del tokens[idx]
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | trailing_semicolon = True
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | break
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | if not trailing_semicolon:
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | return src, False
0030 0015 0014 0000 0010 0006 0000 -- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | return tokens_to_src(tokens), True
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | def put_trailing_semicolon_back(src: str, has_trailing_semicolon: bool) -> str:
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | """Put trailing semicolon back if cell originally had it.
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 |
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | ``tokenize_rt`` so that round-tripping works fine.
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | """
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | if not has_trailing_semicolon:
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | return src
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | from tokenize_rt import reversed_enumerate, src_to_tokens, tokens_to_src
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 |
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | tokens = src_to_tokens(src)
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | for idx, token in reversed_enumerate(tokens):
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | if token.name in TOKENS_TO_IGNORE:
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | continue
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | tokens[idx] = token._replace(src=token.src + ";")
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | break
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | else: # pragma: nocover
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | raise AssertionError(
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | "INTERNAL ERROR: Was not able to reinstate trailing semicolon. "
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | "Please report a bug on https://github.com/psf/black/issues. "
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | ) from None
0022 0014 0016 0001 0004 0002 0000 -- 05 003 005 003 005 008 008 0024.00 0036.00 0001.50 | return str(tokens_to_src(tokens))
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | def mask_cell(src: str) -> Tuple[str, List[Replacement]]:
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | """Mask IPython magics so content becomes parseable Python code.
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | For example,
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | %matplotlib inline
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | 'foo'
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | becomes
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | "25716f358c32750e"
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | 'foo'
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | The replacements are returned, along with the transformed code.
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | """
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | replacements: List[Replacement] = []
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | try:
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | ast.parse(src)
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | except SyntaxError:
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | # Might have IPython magics, will process below.
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | pass
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | else:
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | # Syntax is fine, nothing to mask, early return.
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | return src, replacements
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | from IPython.core.inputtransformer2 import TransformerManager
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 |
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | transformer_manager = TransformerManager()
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | transformed = transformer_manager.transform_cell(src)
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | transformed, cell_magic_replacements = replace_cell_magics(transformed)
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | replacements += cell_magic_replacements
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | transformed = transformer_manager.transform_cell(transformed)
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | transformed, magic_replacements = replace_magics(transformed)
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | if len(transformed.splitlines()) != len(src.splitlines()):
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | # Multi-line magic, not supported.
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | raise NothingChanged
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | replacements += magic_replacements
0038 0021 0019 0003 0009 0007 0003 -- 04 002 005 003 006 007 009 0025.27 0030.32 0001.20 | return transformed, replacements
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | def get_token(src: str, magic: str) -> str:
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | """Return randomly generated token to mask IPython magic with.
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 |
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | For example, if 'magic' was `%matplotlib inline`, then a possible
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | token to mask it with would be `"43fdd17f7e5ddc83"`. The token
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | will be the same length as the magic, and we make sure that it was
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | not already present anywhere else in the cell.
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | """
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | assert magic
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | nbytes = max(len(magic) // 2 - 1, 1)
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | token = TOKEN_HEX(nbytes)
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | counter = 0
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | while token in src:
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | token = TOKEN_HEX(nbytes)
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | counter += 1
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | if counter > 100:
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | raise AssertionError(
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | "INTERNAL ERROR: Black was not able to replace IPython magic. "
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | "Please report a bug on https://github.com/psf/black/issues. "
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | f"The magic might be helpful: {magic}"
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | ) from None
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | if len(token) + 2 < len(magic):
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | token = f"{token}."
0024 0014 0017 0000 0006 0001 0000 -- 04 006 011 007 014 017 021 0085.84 0327.74 0003.82 | return f'"{token}"'
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | def replace_cell_magics(src: str) -> Tuple[str, List[Replacement]]:
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """Replace cell magic with token.
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | Note that 'src' will already have been processed by IPython's
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | TransformerManager().transform_cell.
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | Example,
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | get_ipython().run_cell_magic('t', '-n1', 'ls =!ls\\n')
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | becomes
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | "a794."
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | ls =!ls
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | The replacement, along with the transformed code, is returned.
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | replacements: List[Replacement] = []
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | tree = ast.parse(src)
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | cell_magic_finder = CellMagicFinder()
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | cell_magic_finder.visit(tree)
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | if cell_magic_finder.cell_magic is None:
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | return src, replacements
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | header = cell_magic_finder.cell_magic.header
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | mask = get_token(src, header)
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | replacements.append(Replacement(mask=mask, src=header))
0029 0013 0011 0000 0010 0008 0000 -- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | return f"{mask}\n{cell_magic_finder.cell_magic.body}", replacements
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | def replace_magics(src: str) -> Tuple[str, List[Replacement]]:
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | """Replace magics within body of cell.
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | Note that 'src' will already have been processed by IPython's
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | TransformerManager().transform_cell.
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | Example, this
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | get_ipython().run_line_magic('matplotlib', 'inline')
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | 'foo'
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | becomes
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | "5e67db56d490fd39"
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | 'foo'
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 |
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | The replacement, along with the transformed code, are returned.
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | """
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | replacements = []
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | magic_finder = MagicFinder()
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | magic_finder.visit(ast.parse(src))
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | new_srcs = []
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | for i, line in enumerate(src.splitlines(), start=1):
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | if i in magic_finder.magics:
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | offsets_and_magics = magic_finder.magics[i]
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | if len(offsets_and_magics) != 1: # pragma: nocover
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | raise AssertionError(
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | f"Expecting one magic per line, got: {offsets_and_magics}\n"
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | "Please report a bug on https://github.com/psf/black/issues."
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | )
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | col_offset, magic = (
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | offsets_and_magics[0].col_offset,
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | offsets_and_magics[0].magic,
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | )
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | mask = get_token(src, magic)
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | replacements.append(Replacement(mask=mask, src=magic))
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | line = line[:col_offset] + mask
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | new_srcs.append(line)
0039 0018 0022 0001 0011 0006 0000 -- 04 003 006 003 006 009 009 0028.53 0042.79 0001.50 | return "\n".join(new_srcs), replacements
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def unmask_cell(src: str, replacements: List[Replacement]) -> str:
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """Remove replacements from cell.
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | For example
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | "9b20"
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | foo = bar
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | becomes
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | %%time
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | foo = bar
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | for replacement in replacements:
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | src = src.replace(replacement.mask, replacement.src)
0016 0005 0004 0000 0008 0004 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return src
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | def _is_ipython_magic(node: ast.expr) -> TypeGuard[ast.Attribute]:
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | """Check if attribute is IPython magic.
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 |
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | Note that the source of the abstract syntax tree
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | will already have been processed by IPython's
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | TransformerManager().transform_cell.
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | """
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | return (
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | isinstance(node, ast.Attribute)
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | and isinstance(node.value, ast.Call)
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | and isinstance(node.value.func, ast.Name)
0013 0003 0007 0000 0005 0001 0000 -- 04 002 006 002 006 008 008 0024.00 0024.00 0001.00 | and node.value.func.id == "get_ipython"
0013 0003 0007 0000 0005 0001 0000 -- -- 002 006 002 006 008 008 0024.00 0024.00 0001.00 | )
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def _get_str_args(args: List[ast.expr]) -> List[str]:
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | str_args = []
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | for arg in args:
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | assert isinstance(arg, ast.Str)
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | str_args.append(arg.s)
0006 0006 0006 0000 0000 0000 0000 -- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return str_args
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | @dataclasses.dataclass(frozen=True)
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- | class CellMagic:
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- | name: str
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- | params: Optional[str]
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- | body: str
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 03 -- --- --- --- --- --- --- ------- ------- ------- | @property
0005 0005 0005 0000 0000 0000 0000 03 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def header(self) -> str:
0005 0005 0005 0000 0000 0000 0000 03 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | if self.params:
0005 0005 0005 0000 0000 0000 0000 03 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return f"%%{self.name} {self.params}"
0005 0005 0005 0000 0000 0000 0000 03 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return f"%%{self.name}"
0005 0005 0005 0000 0000 0000 0000 -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | # ast.NodeVisitor + dataclass = breakage under mypyc.
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | class CellMagicFinder(ast.NodeVisitor):
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | """Find cell magics.
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | Note that the source of the abstract syntax tree
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | will already have been processed by IPython's
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | TransformerManager().transform_cell.
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | For example,
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | %%time\n
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | foo()
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | would have been transformed to
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | get_ipython().run_cell_magic('time', '', 'foo()\\n')
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | and we look for instances of the latter.
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- | """
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
0002 0002 0002 0000 0000 0000 0000 04 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def __init__(self, cell_magic: Optional[CellMagic] = None) -> None:
0002 0002 0002 0000 0000 0000 0000 04 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | self.cell_magic = cell_magic
---- ---- ---- ---- ---- ---- ---- 04 -- --- --- --- --- --- --- ------- ------- ------- |
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | def visit_Expr(self, node: ast.Expr) -> None:
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | """Find cell magic, extract header and body."""
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | if (
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | isinstance(node.value, ast.Call)
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | and _is_ipython_magic(node.value.func)
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | and node.value.func.attr == "run_cell_magic"
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | ):
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | args = _get_str_args(node.value.args)
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | self.cell_magic = CellMagic(name=args[0], params=args[1], body=args[2])
0010 0006 0009 0000 0000 0000 0001 04 04 002 005 002 005 007 007 0019.65 0019.65 0001.00 | self.generic_visit(node)
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | @dataclasses.dataclass(frozen=True)
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | class OffsetAndMagic:
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | col_offset: int
---- ---- ---- ---- ---- ---- ---- 01 -- --- --- --- --- --- --- ------- ------- ------- | magic: str
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | # Unsurprisingly, subclassing ast.NodeVisitor means we can't use dataclasses here
---- ---- ---- ---- ---- ---- ---- -- -- --- --- --- --- --- --- ------- ------- ------- | # as mypyc will generate broken code.
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | class MagicFinder(ast.NodeVisitor):
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | """Visit cell to look for get_ipython calls.
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | Note that the source of the abstract syntax tree
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | will already have been processed by IPython's
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | TransformerManager().transform_cell.
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | For example,
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | %matplotlib inline
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | would have been transformed to
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | get_ipython().run_line_magic('matplotlib', 'inline')
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | and we look for instances of the latter (and likewise for other
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | types of magics).
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- | """
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
0002 0003 0002 0000 0000 0000 0000 06 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def __init__(self) -> None:
0002 0003 0002 0000 0000 0000 0000 06 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | self.magics: Dict[int, List[OffsetAndMagic]] = collections.defaultdict(list)
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | def visit_Assign(self, node: ast.Assign) -> None:
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | """Look for system assign magics.
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | For example,
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | black_version = !black --version
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | env = %env var
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | would have been (respectively) transformed to
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | black_version = get_ipython().getoutput('black --version')
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | env = get_ipython().run_line_magic('env', 'var')
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 |
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | and we look for instances of any of the latter.
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | """
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func):
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | args = _get_str_args(node.value.args)
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | if node.value.func.attr == "getoutput":
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | src = f"!{args[0]}"
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | elif node.value.func.attr == "run_line_magic":
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | src = f"%{args[0]}"
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | if args[1]:
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | src += f" {args[1]}"
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | else:
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | raise AssertionError(
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | f"Unexpected IPython magic {node.value.func.attr!r} found. "
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | "Please report a bug on https://github.com/psf/black/issues."
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | ) from None
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | self.magics[node.value.lineno].append(
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | OffsetAndMagic(node.value.col_offset, src)
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | )
0032 0014 0018 0000 0009 0005 0000 06 06 003 007 004 008 010 012 0039.86 0068.34 0001.71 | self.generic_visit(node)
---- ---- ---- ---- ---- ---- ---- 06 -- --- --- --- --- --- --- ------- ------- ------- |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | def visit_Expr(self, node: ast.Expr) -> None:
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | """Look for magics in body of cell.
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | For examples,
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | !ls
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | !!ls
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | ?ls
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | ??ls
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | would (respectively) get transformed to
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | get_ipython().system('ls')
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | get_ipython().getoutput('ls')
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | get_ipython().run_line_magic('pinfo', 'ls')
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | get_ipython().run_line_magic('pinfo2', 'ls')
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 |
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | and we look for instances of any of the latter.
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | """
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func):
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | args = _get_str_args(node.value.args)
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | if node.value.func.attr == "run_line_magic":
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | if args[0] == "pinfo":
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src = f"?{args[1]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | elif args[0] == "pinfo2":
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src = f"??{args[1]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | else:
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src = f"%{args[0]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | if args[1]:
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src += f" {args[1]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | elif node.value.func.attr == "system":
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src = f"!{args[0]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | elif node.value.func.attr == "getoutput":
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | src = f"!!{args[0]}"
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | else:
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | raise NothingChanged # unsupported magic.
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | self.magics[node.value.lineno].append(
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | OffsetAndMagic(node.value.col_offset, src)
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | )
0040 0021 0022 0001 0013 0005 0000 06 09 003 012 007 014 015 021 0082.04 0143.58 0001.75 | self.generic_visit(node)