summaryrefslogtreecommitdiffstats
path: root/2025/info/swanky-after.md
blob: 53c843152cce7e134acbbdd2939c903228d0e773 (plain) (blame)
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
<!-- Automatically generated by emacsconf-publish-after-page -->


<div class="transcript transcript-mainVideo"><a name="swanky-mainVideo-transcript"></a><h1>Transcript</h1>

[[!template text="""Hello everyone, I'm Scott""" start="00:00:00.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and I'll be talking about Swanky Python,""" start="00:00:02.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which is a development environment for Python""" start="00:00:04.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""based on Emacs' Slime package.""" start="00:00:06.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So what is that and why might you find it interesting?""" start="00:00:08.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""SLIME is the Superior Lisp Interaction Mode for Emacs.""" start="00:00:11.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""It's an Emacs package for developing Common Lisp,""" start="00:00:15.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and it's a bit different from the way we develop most languages""" start="00:00:18.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""in that you're always connected""" start="00:00:20.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""to a running instance of your application,""" start="00:00:22.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and you kind of build up your application, piece by piece,""" start="00:00:25.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""modifying one expression at a time""" start="00:00:27.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""without ever having to restart your application.""" start="00:00:30.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So why might you want to develop this way?""" start="00:00:34.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""One advantage is that you can get a faster feedback loop.""" start="00:00:36.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""For some kinds of software, it doesn't make a big difference.""" start="00:00:40.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Like, if you're developing a web backend""" start="00:00:42.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""where all state is stored externally in a database,""" start="00:00:43.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""then you can have a file watcher""" start="00:00:48.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that just restarts the whole Python process""" start="00:00:50.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""whenever you make any edit,""" start="00:00:52.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and you're not really losing anything,""" start="00:00:54.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because all the state is stored outside the Python process""" start="00:00:56.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""in a database. So it works great.""" start="00:00:59.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But for other kinds of software, like""" start="00:01:01.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""let's say you're developing an Emacs package""" start="00:01:03.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""or a video game,""" start="00:01:05.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""then it can be a real pain to restart the application""" start="00:01:07.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and recreate the state it was in before""" start="00:01:10.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""just to test the effect of each edit you want to make.""" start="00:01:12.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Another advantage is the runtime introspection you have available.""" start="00:01:17.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So since you're always connected""" start="00:01:21.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""to a running instance of your application,""" start="00:01:22.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you can inspect the values of variables,""" start="00:01:25.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you can trace functions, and all sorts of other information""" start="00:01:27.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""to help you understand your application better.""" start="00:01:30.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And lastly, it's just a lot of fun to develop this way,""" start="00:01:36.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""or at least I find it fun developing with SLIME,""" start="00:01:39.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so I wrote a SLIME backend for Python""" start="00:01:43.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so I could have more fun when I'm coding in Python.""" start="00:01:45.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""As for the name swanky-python, within SLIME,""" start="00:01:48.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""swank is the name of the Common Lisp backend""" start="00:01:52.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that runs within your Common Lisp application""" start="00:01:56.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and connects to Emacs. So I'm not too creative.""" start="00:01:59.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""swanky-python is just a swank implementation in Python.""" start="00:02:02.920" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Demo""" start="00:02:08.000" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""So let's see it in action. So we started up with M-x slime.""" start="00:02:08.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And what that does is it starts a Python process,""" start="00:02:15.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""starts swanky-python within it, and connects to it from Emacs.""" start="00:02:19.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And you can configure how exactly it runs Python.""" start="00:02:25.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Or you can start swanky python manually""" start="00:02:29.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""within a Python application running on a remote server""" start="00:02:32.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and forward the port locally""" start="00:02:35.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and connect to it in Emacs, from Emacs remotely.""" start="00:02:36.614" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Within the README, there's more documentation""" start="00:02:40.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""on other ways to start it.""" start="00:02:43.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But just M-x slime is the basic way that works most of the time.""" start="00:02:45.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So within the REPL, the first thing you'll notice is that""" start="00:02:52.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""REPL outputs are clickable buttons,""" start="00:02:55.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""what SLIME calls presentations.""" start="00:02:58.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So you can do things like inspect them.""" start="00:03:02.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And for each presentation, in the Python backend,""" start="00:03:04.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it holds on to the reference to the object.""" start="00:03:09.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So for an int, it's not too interesting,""" start="00:03:12.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but let's do a more complex object like a file.""" start="00:03:14.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Then we can inspect the file.""" start="00:03:20.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can describe it, which will bring up documentation""" start="00:03:22.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""on that class. We can use it in further expressions""" start="00:03:26.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""like if we copy it, it will use the actual Python object""" start="00:03:33.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""in this expression.""" start="00:03:39.432" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can assign it to a variable.""" start="00:03:43.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""SLIME uses presentations everywhere""" start="00:03:48.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that a Python object would be displayed.""" start="00:03:51.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So instead of just their string representation,""" start="00:03:53.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""when you have a backtrace on an exception,""" start="00:03:56.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""or you... within the inspector or anywhere else really,""" start="00:04:00.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""anywhere that the string representation""" start="00:04:03.966" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""of an object would be displayed,""" start="00:04:06.020" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it displays a presentation that you can go on to""" start="00:04:07.941" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""inspect, reuse, or send to the REPL and so on.""" start="00:04:10.741" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""One useful utility function is pp for print presentation.""" start="00:04:14.961" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We haven't imported it yet.""" start="00:04:23.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So when we get a name error exception""" start="00:04:25.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and SLIME sees that that name is available for import somewhere,""" start="00:04:29.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it'll give us the option of importing it.""" start="00:04:33.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Since it's available for import from multiple modules,""" start="00:04:38.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it'll prompt us for which one we want to import it from.""" start="00:04:40.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We want to import it from swanky-python,""" start="00:04:43.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""not from the standard library.""" start="00:04:45.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Then it will print a presentation of that object.""" start="00:04:48.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Within the REPL, this is not really useful""" start="00:04:52.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because all REPL outputs are already presentations.""" start="00:04:55.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But I use this now whenever I would use print debugging,""" start="00:04:58.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""just whenever I would use insert print statements in my program""" start="00:05:02.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""to see what's going on, I have it print a presentation""" start="00:05:05.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because that way I can go back and inspect it later,""" start="00:05:08.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""copy it to the REPL and further manipulate it and so on.""" start="00:05:11.200" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Inspector""" start="00:05:16.600" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's look at the inspector more.""" start="00:05:16.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""If we go back and inspect the file object,""" start="00:05:20.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you can write custom inspector views""" start="00:05:25.580" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for different kinds of objects.""" start="00:05:27.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So far, I just have a couple. One for sequences,""" start="00:05:28.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""one for mappings, and one for every other kind of object.""" start="00:05:32.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Like if we inspect a mapping, there's a shortcut""" start="00:05:36.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""inspect last result, which is what I normally use""" start="00:05:45.980" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""to open the inspector. Then we see the values,""" start="00:05:48.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and each value in the inspector is a presentation""" start="00:05:52.380" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that we can go on to inspect, and so on.""" start="00:05:56.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Let's go back to inspecting the file object.""" start="00:05:58.420" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Again, we can inspect each of the values,""" start="00:06:03.980" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we can copy them back to the REPL and so on.""" start="00:06:06.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""It just displays all the attributes for the class""" start="00:06:10.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and their values.""" start="00:06:13.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can configure what attributes we want to show.""" start="00:06:15.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""There's a transient menu where we can toggle""" start="00:06:18.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""if we want to show private attributes, dunder attributes,""" start="00:06:21.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""doc strings, so on, or everything,""" start="00:06:23.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which is a bit much to show by default.""" start="00:06:26.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So we'll reset it to the default.""" start="00:06:28.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""In the future, I want to add graphical inspector views""" start="00:06:33.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for different kinds of objects, and also support""" start="00:06:37.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""showing plots in both the inspector and the REPL,""" start="00:06:40.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but that's future work I haven't started on yet.""" start="00:06:43.000" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Evaluating Python""" start="00:06:47.720" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Let's look at the different options for evaluating Python.""" start="00:06:47.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So we can evaluate a whole file.""" start="00:06:52.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can evaluate just a class.""" start="00:06:59.100" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can evaluate just the method we're working on.""" start="00:07:00.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can evaluate a Python statement,""" start="00:07:03.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and it will show the result in an overlay next to the cursor.""" start="00:07:06.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can select some code and just evaluate the highlighted region.""" start="00:07:11.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can sync the REPL to the active file.""" start="00:07:17.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So now everything we evaluate in the REPL will be in the""" start="00:07:24.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""context of the eval_demo module.""" start="00:07:27.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can also set the module that the REPL is in.""" start="00:07:29.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can go back to main.""" start="00:07:35.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But let's go back to the eval_demo module for now.""" start="00:07:38.280" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Updating""" start="00:07:43.680" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""One useful thing is when you update a class or a function,""" start="00:07:43.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it updates old instances of that class or function.""" start="00:07:49.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So right now, f.bar is foobar.""" start="00:07:54.540" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But if we edit that class, it will actually edit the code""" start="00:07:58.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for the old instance of that class.""" start="00:08:03.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And that's provided by code I copied""" start="00:08:05.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""from IPython's autoreload extension.""" start="00:08:07.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""It helps when you're trying to develop in Python""" start="00:08:12.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""without having to restart the Python process""" start="00:08:14.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""whenever you make a change.""" start="00:08:16.499" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Auto reload in Python is a big topic""" start="00:08:20.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that I don't really have time to go into here,""" start="00:08:22.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but right now it is more limited""" start="00:08:26.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""than what is done in Common Lisp.""" start="00:08:29.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Like for example, if you have a data class in Python""" start="00:08:32.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and you add a new field to the data class,""" start="00:08:35.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it won't automatically update old instances""" start="00:08:37.620" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""of the data class with a new field.""" start="00:08:41.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So there's more that needs to be done with that,""" start="00:08:43.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but I am perhaps naively optimistic""" start="00:08:46.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that Python's runtime is quite dynamic and flexible,""" start="00:08:50.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and that I can fully implement autoreload in Python,""" start="00:08:54.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but there's still work to be done,""" start="00:08:59.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and it's a big topic to go into.""" start="00:09:02.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Next up, let's look at the backtrace buffer.""" start="00:09:05.420" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But as it is right now, autoreload is actually useful.""" start="00:09:08.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""I mostly develop in Python without having to restart the process""" start="00:09:12.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and without running into issues from old state""" start="00:09:16.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that hasn't been updated properly.""" start="00:09:19.600" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Backtraces""" start="00:09:22.900" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""So if we go on to look at the backtrace buffer,""" start="00:09:22.900" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""whenever we get an exception in Python...""" start="00:09:26.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Let's go back to it.""" start="00:09:32.820" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Whenever we get an exception, it will...""" start="00:09:37.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""let's change the code so that it actually""" start="00:09:41.420" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""gets an exception...""" start="00:09:43.699" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we will get an interactive backtrace buffer""" start="00:09:49.966" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""where we can browse the source code for the different stack frames""" start="00:09:52.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and the local variables within the stack frames,""" start="00:09:57.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which are all presentations that we can inspect and so on.""" start="00:10:00.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can also open a REPL in the context of any stack frame.""" start="00:10:04.340" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Or we can, when we go to the source for a given stack frame,""" start="00:10:10.620" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we can select some Python code and evaluate it""" start="00:10:16.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""within the context of that stack frame.""" start="00:10:20.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""One major limitation compared to SLIME for Common Lisp""" start="00:10:25.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""is that in Common Lisp, you have the option to""" start="00:10:30.700" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""restart or resume execution from a given stack frame""" start="00:10:33.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""after an exception happens, where in Python,""" start="00:10:38.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""what we have right now is pretty much equivalent to""" start="00:10:42.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""the postmortem debugger.""" start="00:10:45.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You can view the state that the call stack was in""" start="00:10:47.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""at the time of the exception,""" start="00:10:50.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but you can't actually resume execution,""" start="00:10:51.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which you often might want to do,""" start="00:10:55.660" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because when you're coding in a dynamic language,""" start="00:10:57.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you're going to get runtime errors.""" start="00:10:59.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So if you're writing a script that does like some sort of""" start="00:11:01.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""long-running computation or processes a ton of files""" start="00:11:04.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and gets an exception parsing one file halfway through,""" start="00:11:08.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""normally you'd have to fix the script, and then rerun it""" start="00:11:11.940" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and have it process all the same files all over again,""" start="00:11:16.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and lose a bunch of time for every bug you run into""" start="00:11:19.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and fix you have to make.""" start="00:11:23.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So right now we've got a kind of mediocre workaround""" start="00:11:24.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which is you can add the restart decorator to a function""" start="00:11:28.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and then... where in the case of a script""" start="00:11:34.020" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""processing a bunch of files,""" start="00:11:37.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you would add the restart decorator to the function""" start="00:11:38.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that processes a single file.""" start="00:11:41.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You'd add it to the function""" start="00:11:43.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that represents kind of the smallest unit of work""" start="00:11:45.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that might fail with an exception,""" start="00:11:47.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Then, when you get an exception,""" start="00:11:50.220" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you can actually edit the function.""" start="00:11:54.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Like, if we edit it so it doesn't throw an error,""" start="00:11:57.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and then we can resume execution,""" start="00:12:01.020" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""then it will return from foo using the""" start="00:12:07.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""the new version of baz,""" start="00:12:12.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""without having to run the script from the beginning again.""" start="00:12:15.041" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So in the example of a script that processes a bunch of files,""" start="00:12:18.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that would let you,""" start="00:12:22.380" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""as you run into files that cause an exception,""" start="00:12:24.300" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""fix your code to deal with it""" start="00:12:27.620" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and resume execution without having to restart the script""" start="00:12:29.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""from the beginning.""" start="00:12:31.881" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But this is obviously a pretty terrible hack,""" start="00:12:33.081" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""having to add the restart decorator to the function.""" start="00:12:36.121" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""I would like it to be able to restart from any function.""" start="00:12:38.841" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""without needing the decorator, as you can in Common Lisp,""" start="00:12:46.740" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but I think that will require patching CPython""" start="00:12:49.632" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and I really have no idea how to do that.""" start="00:12:54.032" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So if you do know anything about CPython internals""" start="00:12:56.580" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and are interested in helping, please reach out.""" start="00:13:00.532" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""pydumpling""" start="00:13:03.721" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Another feature we have with the backtrace buffer is""" start="00:13:03.721" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""there's this library called PyDumpling""" start="00:13:07.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which can serialize a traceback and store it to a file.""" start="00:13:09.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So you can use PyDumpling with your applications running in""" start="00:13:14.660" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""production to serialize a traceback""" start="00:13:17.860" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""whenever they have an exception and save it to a file.""" start="00:13:21.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Then you can transfer the file locally""" start="00:13:24.900" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and load it into your local Emacs with slime-py-load-pydumpling.""" start="00:13:28.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""This will load the same backtrace buffer,""" start="00:13:38.860" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and you see all the same local variables""" start="00:13:41.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""at the time of the exception.""" start="00:13:44.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You can inspect them and get a REPL""" start="00:13:45.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""in the context of the stack frame.""" start="00:13:48.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Well, this will only work for variables""" start="00:13:51.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that can be serialized with pickle.""" start="00:13:54.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Or actually, the library uses dill,""" start="00:13:57.620" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which can serialize a bit more than pickle can.""" start="00:13:59.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But yeah so this can help you inspect and debug errors""" start="00:14:03.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for applications running in production remotely""" start="00:14:10.201" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that you don't want to have SLIME connected to 24-7.""" start="00:14:12.881" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Documentation browser""" start="00:14:20.060" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's look at the documentation browser.""" start="00:14:20.060" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can bring up documentation for any module,""" start="00:14:24.860" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and all this information is generated""" start="00:14:29.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""from runtime introspection,""" start="00:14:33.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""from the doc strings for the module""" start="00:14:35.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and the classes and so on.""" start="00:14:37.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So you won't see documentation for libraries""" start="00:14:39.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that you don't have actually loaded""" start="00:14:41.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""into your running Python process.""" start="00:14:43.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Then you can go browse to classes.""" start="00:14:45.940" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""It'll show all the attributes, their methods, and so on.""" start="00:14:50.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""By each method to the right, it will show""" start="00:14:54.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""the base class where the method was originally inherited from.""" start="00:14:57.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You can also bring up a screen with all the Python packages""" start="00:15:02.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that are installed, and browse that with imenu,""" start="00:15:09.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and bring up information on any package and so on.""" start="00:15:14.440" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Thread view""" start="00:15:20.360" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's take a look at the thread view.""" start="00:15:20.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So let's run this and then bring up the thread view""" start="00:15:28.500" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and this will show information on all running threads.""" start="00:15:31.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You can configure it to refresh after a given interval,""" start="00:15:35.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""like every second, but I don't have that set up right now,""" start="00:15:38.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so I have to manually refresh it.""" start="00:15:41.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Probably the most useful thing is that""" start="00:15:45.660" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""you can bring up a backtrace for any thread""" start="00:15:47.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which won't pause the thread or anything,""" start="00:15:49.740" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but will just give you the call stack""" start="00:15:51.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""at the time you requested the backtrace.""" start="00:15:53.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""You can again view the stack frames, local variables,""" start="00:15:55.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""open a REPL in the context of the thread, and so on.""" start="00:15:59.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""There's also a viewer for async tasks,""" start="00:16:04.140" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but I'm not going to demo that right now,""" start="00:16:07.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because for that to work, you have to start swanky-python""" start="00:16:10.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""after the async event loop has started,""" start="00:16:14.160" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""from within the same thread.""" start="00:16:16.600" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""If you go to the project readme,""" start="00:16:18.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""there's a demo of how to use the async task viewer""" start="00:16:20.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""with a fastapi project.""" start="00:16:23.920" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Tracing functions""" start="00:16:27.440" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's look at tracing functions.""" start="00:16:27.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So here we got some random error,""" start="00:16:33.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""because this is still very much a work in progress.""" start="00:16:36.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But it looks like it executed""" start="00:16:39.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""correctly this time.""" start="00:16:42.360" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So now let's mark the fibonacci function""" start="00:16:43.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for tracing and execute it.""" start="00:16:47.566" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can see, every time the function is called,""" start="00:16:50.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""all its arguments and return values.""" start="00:16:56.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Again, there are presentations that we can inspect and so on.""" start="00:16:58.240" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But let's inspect a more complex object, like a file object.""" start="00:17:02.900" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""If we trace the count_lines function and run that code,""" start="00:17:06.080" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""then we can inspect the file it was passed, or the file object.""" start="00:17:11.340" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""One pitfall is that in Python, objects are mutable.""" start="00:17:15.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So in the trace buffer, the string representation""" start="00:17:21.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that's printed is the string representation""" start="00:17:25.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""at the time it was passed to the function.""" start="00:17:27.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But when we go to inspect it,""" start="00:17:31.220" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we're inspecting the object as it is right now,""" start="00:17:32.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which can be different than it was at the time""" start="00:17:34.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""the function saw it. So for this file object, for example,""" start="00:17:37.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it's closed now, when it was open at the time""" start="00:17:41.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""the function used it.""" start="00:17:44.280" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""AI integrations""" start="00:17:47.800" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's look at AI integrations.""" start="00:17:47.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So if you're used to SLIME with Common Lisp,""" start="00:17:50.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Emacs actually has a built-in AI that can help with the transition.""" start="00:17:54.520" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So it's just a joke, I actually really like Python.""" start="00:18:09.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""And for more serious AI integrations,""" start="00:18:14.560" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""I have some ideas for the future""" start="00:18:18.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but I haven't implemented anything yet.""" start="00:18:19.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""I think right now, people are mostly passing source code to LLMs""" start="00:18:21.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""but since we're embedded in the Python process at runtime,""" start="00:18:27.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we have a lot of more information available,""" start="00:18:32.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""like maybe we can trace all calls to functions,""" start="00:18:35.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and when we have a bug,""" start="00:18:39.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""we can feed the trace to the LLM,""" start="00:18:41.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and the LLM can point out maybe""" start="00:18:46.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""when this function was called with these arguments,""" start="00:18:48.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""its return value doesn't make sense,""" start="00:18:51.960" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so maybe that's the root cause of your bug.""" start="00:18:53.880" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""If you have any ideas of potential LLM or AI integrations,""" start="00:18:55.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""let me know. I'm happy to discuss.""" start="00:19:02.360" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""LSP-type features""" start="00:19:06.000" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""Next up, let's look at standard LSP-type features.""" start="00:19:06.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So we've got completions. It's fuzzy completions right now,""" start="00:19:09.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so it's showing everything with a PR in the name.""" start="00:19:14.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can bring up documentation for each one.""" start="00:19:16.320" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""When we start calling a method in the minibuffer at the bottom""" start="00:19:21.780" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""it'll show the signature.""" start="00:19:26.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""There's some refactoring available.""" start="00:19:28.860" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""We can extract a function or variable,""" start="00:19:33.720" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""or rename something,""" start="00:19:37.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""like, let's rename fib to fib2,""" start="00:19:39.500" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and it will rename all the uses of it.""" start="00:19:42.920" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""All these features are based on Jedi,""" start="00:19:47.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""which is the Python library used by IPython.""" start="00:19:49.760" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But as it is right now,""" start="00:19:55.400" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""if you want the most complete Python development experience""" start="00:19:57.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""in Emacs, I'd probably recommend using LSP""" start="00:20:02.040" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for everything LSP can do, and then just using swanky-python""" start="00:20:05.580" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""for the object inspector and backtrace buffer,""" start="00:20:10.440" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and the interactive features it has""" start="00:20:13.680" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""that an LSP can't provide.""" start="00:20:15.360" video="mainVideo-swanky" id="subtitle"]]

<div class="transcript-heading">[[!template new="1" text="""Wrapping up""" start="00:20:18.032" video="mainVideo-swanky" id="subtitle"]]</div>[[!template text="""And that's it really.""" start="00:20:18.032" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""Shortly we'll have questions and answers""" start="00:20:23.340" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""as part of EmacsConf, and later on,""" start="00:20:25.866" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""if you have any questions, ideas, or issues""" start="00:20:28.800" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""feel free to reach out over email""" start="00:20:31.200" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""or create an issue on the repository.""" start="00:20:34.640" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""I should probably warn you,""" start="00:20:38.000" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""if you want to try out the project:""" start="00:20:39.332" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so far I'm probably the only user of it""" start="00:20:41.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""and I've only tested it on my own Emacs setup,""" start="00:20:45.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""so it's quite likely you'll run into issues""" start="00:20:48.280" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""trying to get it installed and working.""" start="00:20:50.840" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""But if you do run into problems, please reach out,""" start="00:20:53.480" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""let me know. I'm happy to help and try and fix them.""" start="00:20:56.120" video="mainVideo-swanky" id="subtitle"]]
[[!template text="""So that's it. Thanks for listening.""" start="00:20:59.280" video="mainVideo-swanky" id="subtitle"]]

</div>

Captioner: sachac

Questions or comments? Please e-mail [sczi@disroot.org](mailto:sczi@disroot.org?subject=Comment%20for%20EmacsConf%202023%20swanky%3A%20Swanky%20Python%3A%20Interactive%20development%20for%20Python)


<!-- End of emacsconf-publish-after-page -->