WEBVTT captioned by sachac 00:00:00.880 --> 00:00:02.439 Hello everyone, I'm Scott 00:00:02.440 --> 00:00:04.239 and I'll be talking about Swanky Python, 00:00:04.240 --> 00:00:06.199 which is a development environment for Python 00:00:06.200 --> 00:00:08.319 based on Emacs' Slime package. 00:00:08.320 --> 00:00:11.679 So what is that and why might you find it interesting? 00:00:11.680 --> 00:00:15.279 SLIME is the Superior Lisp Interaction Mode for Emacs. 00:00:15.280 --> 00:00:17.999 It's an Emacs package for developing Common Lisp, 00:00:18.000 --> 00:00:20.679 and it's a bit different from the way we develop most languages 00:00:20.680 --> 00:00:22.599 in that you're always connected 00:00:22.600 --> 00:00:25.399 to a running instance of your application, 00:00:25.400 --> 00:00:27.959 and you kind of build up your application, piece by piece, 00:00:27.960 --> 00:00:30.399 modifying one expression at a time 00:00:30.400 --> 00:00:34.559 without ever having to restart your application. 00:00:34.560 --> 00:00:36.679 So why might you want to develop this way? 00:00:36.680 --> 00:00:40.039 One advantage is that you can get a faster feedback loop. 00:00:40.040 --> 00:00:42.599 For some kinds of software, it doesn't make a big difference. 00:00:42.600 --> 00:00:43.919 Like, if you're developing a web backend 00:00:43.920 --> 00:00:48.039 where all state is stored externally in a database, 00:00:48.040 --> 00:00:50.279 then you can have a file watcher 00:00:50.280 --> 00:00:52.799 that just restarts the whole Python process 00:00:52.800 --> 00:00:54.639 whenever you make any edit, 00:00:54.640 --> 00:00:56.159 and you're not really losing anything, 00:00:56.160 --> 00:00:59.679 because all the state is stored outside the Python process 00:00:59.680 --> 00:01:01.719 in a database. So it works great. 00:01:01.720 --> 00:01:03.559 But for other kinds of software, like 00:01:03.560 --> 00:01:05.559 let's say you're developing an Emacs package 00:01:05.560 --> 00:01:07.279 or a video game, 00:01:07.280 --> 00:01:10.319 then it can be a real pain to restart the application 00:01:10.320 --> 00:01:12.679 and recreate the state it was in before 00:01:12.680 --> 00:01:17.279 just to test the effect of each edit you want to make. 00:01:17.280 --> 00:01:21.359 Another advantage is the runtime introspection you have available. 00:01:21.360 --> 00:01:22.679 So since you're always connected 00:01:22.680 --> 00:01:24.999 to a running instance of your application, 00:01:25.000 --> 00:01:27.799 you can inspect the values of variables, 00:01:27.800 --> 00:01:30.959 you can trace functions, and all sorts of other information 00:01:30.960 --> 00:01:36.279 to help you understand your application better. 00:01:36.280 --> 00:01:39.919 And lastly, it's just a lot of fun to develop this way, 00:01:39.920 --> 00:01:43.519 or at least I find it fun developing with SLIME, 00:01:43.520 --> 00:01:45.759 so I wrote a SLIME backend for Python 00:01:45.760 --> 00:01:48.799 so I could have more fun when I'm coding in Python. 00:01:48.800 --> 00:01:52.599 As for the name swanky-python, within SLIME, 00:01:52.600 --> 00:01:56.279 swank is the name of the Common Lisp backend 00:01:56.280 --> 00:01:59.199 that runs within your Common Lisp application 00:01:59.200 --> 00:02:02.919 and connects to Emacs. So I'm not too creative. 00:02:02.920 --> 00:02:07.999 swanky-python is just a swank implementation in Python. NOTE Demo 00:02:08.000 --> 00:02:15.279 So let's see it in action. So we started up with M-x slime. 00:02:15.280 --> 00:02:19.639 And what that does is it starts a Python process, 00:02:19.640 --> 00:02:25.039 starts swanky-python within it, and connects to it from Emacs. 00:02:25.040 --> 00:02:29.039 And you can configure how exactly it runs Python. 00:02:29.040 --> 00:02:32.479 Or you can start swanky python manually 00:02:32.480 --> 00:02:35.119 within a Python application running on a remote server 00:02:35.120 --> 00:02:36.313 and forward the port locally 00:02:36.614 --> 00:02:40.919 and connect to it in Emacs, from Emacs remotely. 00:02:40.920 --> 00:02:43.239 Within the README, there's more documentation 00:02:43.240 --> 00:02:45.519 on other ways to start it. 00:02:45.520 --> 00:02:52.159 But just M-x slime is the basic way that works most of the time. 00:02:52.160 --> 00:02:55.759 So within the REPL, the first thing you'll notice is that 00:02:55.760 --> 00:02:58.839 REPL outputs are clickable buttons, 00:02:58.840 --> 00:03:02.119 what SLIME calls presentations. 00:03:02.120 --> 00:03:04.759 So you can do things like inspect them. 00:03:04.760 --> 00:03:09.759 And for each presentation, in the Python backend, 00:03:09.760 --> 00:03:12.479 it holds on to the reference to the object. 00:03:12.480 --> 00:03:14.559 So for an int, it's not too interesting, 00:03:14.560 --> 00:03:20.239 but let's do a more complex object like a file. 00:03:20.240 --> 00:03:22.519 Then we can inspect the file. 00:03:22.520 --> 00:03:26.599 We can describe it, which will bring up documentation 00:03:26.600 --> 00:03:33.759 on that class. We can use it in further expressions 00:03:33.760 --> 00:03:39.431 like if we copy it, it will use the actual Python object 00:03:39.432 --> 00:03:43.399 in this expression. 00:03:43.400 --> 00:03:48.319 We can assign it to a variable. 00:03:48.320 --> 00:03:50.999 SLIME uses presentations everywhere 00:03:51.000 --> 00:03:53.239 that a Python object would be displayed. 00:03:53.240 --> 00:03:56.559 So instead of just their string representation, 00:03:56.560 --> 00:04:00.239 when you have a backtrace on an exception, 00:04:00.240 --> 00:04:03.965 or you... within the inspector or anywhere else really, 00:04:03.966 --> 00:04:06.019 anywhere that the string representation 00:04:06.020 --> 00:04:07.940 of an object would be displayed, 00:04:07.941 --> 00:04:10.740 it displays a presentation that you can go on to 00:04:10.741 --> 00:04:14.960 inspect, reuse, or send to the REPL and so on. 00:04:14.961 --> 00:04:23.039 One useful utility function is pp for print presentation. 00:04:23.040 --> 00:04:25.119 We haven't imported it yet. 00:04:25.120 --> 00:04:29.159 So when we get a name error exception 00:04:29.160 --> 00:04:33.879 and SLIME sees that that name is available for import somewhere, 00:04:33.880 --> 00:04:38.279 it'll give us the option of importing it. 00:04:38.280 --> 00:04:40.599 Since it's available for import from multiple modules, 00:04:40.600 --> 00:04:43.919 it'll prompt us for which one we want to import it from. 00:04:43.920 --> 00:04:45.519 We want to import it from swanky-python, 00:04:45.520 --> 00:04:48.479 not from the standard library. 00:04:48.480 --> 00:04:52.599 Then it will print a presentation of that object. 00:04:52.600 --> 00:04:55.559 Within the REPL, this is not really useful 00:04:55.560 --> 00:04:58.919 because all REPL outputs are already presentations. 00:04:58.920 --> 00:05:02.799 But I use this now whenever I would use print debugging, 00:05:02.800 --> 00:05:05.639 just whenever I would use insert print statements in my program 00:05:05.640 --> 00:05:08.399 to see what's going on, I have it print a presentation 00:05:08.400 --> 00:05:11.199 because that way I can go back and inspect it later, 00:05:11.200 --> 00:05:16.599 copy it to the REPL and further manipulate it and so on. NOTE Inspector 00:05:16.600 --> 00:05:20.119 Next up, let's look at the inspector more. 00:05:20.120 --> 00:05:25.579 If we go back and inspect the file object, 00:05:25.580 --> 00:05:27.239 you can write custom inspector views 00:05:27.240 --> 00:05:28.839 for different kinds of objects. 00:05:28.840 --> 00:05:32.519 So far, I just have a couple. One for sequences, 00:05:32.520 --> 00:05:36.919 one for mappings, and one for every other kind of object. 00:05:36.920 --> 00:05:45.979 Like if we inspect a mapping, there's a shortcut 00:05:45.980 --> 00:05:48.639 inspect last result, which is what I normally use 00:05:48.640 --> 00:05:52.379 to open the inspector. Then we see the values, 00:05:52.380 --> 00:05:56.319 and each value in the inspector is a presentation 00:05:56.320 --> 00:05:58.419 that we can go on to inspect, and so on. 00:05:58.420 --> 00:06:03.979 Let's go back to inspecting the file object. 00:06:03.980 --> 00:06:06.039 Again, we can inspect each of the values, 00:06:06.040 --> 00:06:10.239 we can copy them back to the REPL and so on. 00:06:10.240 --> 00:06:13.839 It just displays all the attributes for the class 00:06:13.840 --> 00:06:15.399 and their values. 00:06:15.400 --> 00:06:18.119 We can configure what attributes we want to show. 00:06:18.120 --> 00:06:21.119 There's a transient menu where we can toggle 00:06:21.120 --> 00:06:23.359 if we want to show private attributes, dunder attributes, 00:06:23.360 --> 00:06:26.439 doc strings, so on, or everything, 00:06:26.440 --> 00:06:28.519 which is a bit much to show by default. 00:06:28.520 --> 00:06:33.719 So we'll reset it to the default. 00:06:33.720 --> 00:06:37.839 In the future, I want to add graphical inspector views 00:06:37.840 --> 00:06:40.679 for different kinds of objects, and also support 00:06:40.680 --> 00:06:42.999 showing plots in both the inspector and the REPL, 00:06:43.000 --> 00:06:47.719 but that's future work I haven't started on yet. NOTE Evaluating Python 00:06:47.720 --> 00:06:51.999 Let's look at the different options for evaluating Python. 00:06:52.000 --> 00:06:59.099 So we can evaluate a whole file. 00:06:59.100 --> 00:07:00.639 We can evaluate just a class. 00:07:00.640 --> 00:07:03.479 We can evaluate just the method we're working on. 00:07:03.480 --> 00:07:06.359 We can evaluate a Python statement, 00:07:06.360 --> 00:07:11.839 and it will show the result in an overlay next to the cursor. 00:07:11.840 --> 00:07:17.919 We can select some code and just evaluate the highlighted region. 00:07:17.920 --> 00:07:24.799 We can sync the REPL to the active file. 00:07:24.800 --> 00:07:27.319 So now everything we evaluate in the REPL will be in the 00:07:27.320 --> 00:07:29.639 context of the eval_demo module. 00:07:29.640 --> 00:07:35.399 We can also set the module that the REPL is in. 00:07:35.400 --> 00:07:38.279 We can go back to main. 00:07:38.280 --> 00:07:43.679 But let's go back to the eval_demo module for now. NOTE Updating 00:07:43.680 --> 00:07:49.799 One useful thing is when you update a class or a function, 00:07:49.800 --> 00:07:54.539 it updates old instances of that class or function. 00:07:54.540 --> 00:07:58.479 So right now, f.bar is foobar. 00:07:58.480 --> 00:08:03.719 But if we edit that class, it will actually edit the code 00:08:03.720 --> 00:08:05.239 for the old instance of that class. 00:08:05.240 --> 00:08:07.599 And that's provided by code I copied 00:08:07.600 --> 00:08:12.079 from IPython's autoreload extension. 00:08:12.080 --> 00:08:14.639 It helps when you're trying to develop in Python 00:08:14.640 --> 00:08:16.498 without having to restart the Python process 00:08:16.499 --> 00:08:20.039 whenever you make a change. 00:08:20.040 --> 00:08:22.599 Auto reload in Python is a big topic 00:08:22.600 --> 00:08:26.519 that I don't really have time to go into here, 00:08:26.520 --> 00:08:29.479 but right now it is more limited 00:08:29.480 --> 00:08:32.559 than what is done in Common Lisp. 00:08:32.560 --> 00:08:35.759 Like for example, if you have a data class in Python 00:08:35.760 --> 00:08:37.619 and you add a new field to the data class, 00:08:37.620 --> 00:08:41.039 it won't automatically update old instances 00:08:41.040 --> 00:08:43.399 of the data class with a new field. 00:08:43.400 --> 00:08:46.599 So there's more that needs to be done with that, 00:08:46.600 --> 00:08:50.359 but I am perhaps naively optimistic 00:08:50.360 --> 00:08:54.279 that Python's runtime is quite dynamic and flexible, 00:08:54.280 --> 00:08:59.799 and that I can fully implement autoreload in Python, 00:08:59.800 --> 00:09:02.119 but there's still work to be done, 00:09:02.120 --> 00:09:05.419 and it's a big topic to go into. 00:09:05.420 --> 00:09:08.959 Next up, let's look at the backtrace buffer. 00:09:08.960 --> 00:09:12.839 But as it is right now, autoreload is actually useful. 00:09:12.840 --> 00:09:16.959 I mostly develop in Python without having to restart the process 00:09:16.960 --> 00:09:19.599 and without running into issues from old state 00:09:19.600 --> 00:09:22.899 that hasn't been updated properly. NOTE Backtraces 00:09:22.900 --> 00:09:25.999 So if we go on to look at the backtrace buffer, 00:09:26.000 --> 00:09:32.819 whenever we get an exception in Python... 00:09:32.820 --> 00:09:37.079 Let's go back to it. 00:09:37.080 --> 00:09:41.419 Whenever we get an exception, it will... 00:09:41.420 --> 00:09:43.698 let's change the code so that it actually 00:09:43.699 --> 00:09:49.965 gets an exception... 00:09:49.966 --> 00:09:52.519 we will get an interactive backtrace buffer 00:09:52.520 --> 00:09:57.599 where we can browse the source code for the different stack frames 00:09:57.600 --> 00:10:00.199 and the local variables within the stack frames, 00:10:00.200 --> 00:10:03.439 which are all presentations that we can inspect and so on. 00:10:04.340 --> 00:10:10.619 We can also open a REPL in the context of any stack frame. 00:10:10.620 --> 00:10:16.439 Or we can, when we go to the source for a given stack frame, 00:10:16.440 --> 00:10:20.359 we can select some Python code and evaluate it 00:10:20.360 --> 00:10:25.959 within the context of that stack frame. 00:10:25.960 --> 00:10:30.699 One major limitation compared to SLIME for Common Lisp 00:10:30.700 --> 00:10:33.759 is that in Common Lisp, you have the option to 00:10:33.760 --> 00:10:38.159 restart or resume execution from a given stack frame 00:10:38.160 --> 00:10:42.439 after an exception happens, where in Python, 00:10:42.440 --> 00:10:45.799 what we have right now is pretty much equivalent to 00:10:45.800 --> 00:10:47.159 the postmortem debugger. 00:10:47.160 --> 00:10:50.839 You can view the state that the call stack was in 00:10:50.840 --> 00:10:51.959 at the time of the exception, 00:10:51.960 --> 00:10:55.659 but you can't actually resume execution, 00:10:55.660 --> 00:10:57.559 which you often might want to do, 00:10:57.560 --> 00:10:59.919 because when you're coding in a dynamic language, 00:10:59.920 --> 00:11:01.479 you're going to get runtime errors. 00:11:01.480 --> 00:11:04.119 So if you're writing a script that does like some sort of 00:11:04.120 --> 00:11:07.999 long-running computation or processes a ton of files 00:11:08.000 --> 00:11:11.939 and gets an exception parsing one file halfway through, 00:11:11.940 --> 00:11:16.919 normally you'd have to fix the script, and then rerun it 00:11:16.920 --> 00:11:19.759 and have it process all the same files all over again, 00:11:19.760 --> 00:11:23.839 and lose a bunch of time for every bug you run into 00:11:23.840 --> 00:11:24.879 and fix you have to make. 00:11:24.880 --> 00:11:28.679 So right now we've got a kind of mediocre workaround 00:11:28.680 --> 00:11:34.019 which is you can add the restart decorator to a function 00:11:34.020 --> 00:11:37.239 and then... where in the case of a script 00:11:37.240 --> 00:11:38.879 processing a bunch of files, 00:11:38.880 --> 00:11:41.799 you would add the restart decorator to the function 00:11:41.800 --> 00:11:43.599 that processes a single file. 00:11:43.600 --> 00:11:45.439 You'd add it to the function 00:11:45.440 --> 00:11:47.879 that represents kind of the smallest unit of work 00:11:47.880 --> 00:11:50.219 that might fail with an exception, 00:11:50.220 --> 00:11:54.359 Then, when you get an exception, 00:11:54.360 --> 00:11:57.479 you can actually edit the function. 00:11:57.480 --> 00:12:01.019 Like, if we edit it so it doesn't throw an error, 00:12:01.020 --> 00:12:07.199 and then we can resume execution, 00:12:07.200 --> 00:12:12.799 then it will return from foo using the 00:12:12.800 --> 00:12:15.040 the new version of baz, 00:12:15.041 --> 00:12:18.559 without having to run the script from the beginning again. 00:12:18.560 --> 00:12:22.379 So in the example of a script that processes a bunch of files, 00:12:22.380 --> 00:12:24.299 that would let you, 00:12:24.300 --> 00:12:27.619 as you run into files that cause an exception, 00:12:27.620 --> 00:12:29.079 fix your code to deal with it 00:12:29.080 --> 00:12:31.880 and resume execution without having to restart the script 00:12:31.881 --> 00:12:33.080 from the beginning. 00:12:33.081 --> 00:12:36.120 But this is obviously a pretty terrible hack, 00:12:36.121 --> 00:12:38.840 having to add the restart decorator to the function. 00:12:38.841 --> 00:12:46.739 I would like it to be able to restart from any function. 00:12:46.740 --> 00:12:49.631 without needing the decorator, as you can in Common Lisp, 00:12:49.632 --> 00:12:54.031 but I think that will require patching CPython 00:12:54.032 --> 00:12:56.579 and I really have no idea how to do that. 00:12:56.580 --> 00:13:00.531 So if you do know anything about CPython internals 00:13:00.532 --> 00:13:03.720 and are interested in helping, please reach out. NOTE pydumpling 00:13:03.721 --> 00:13:07.119 Another feature we have with the backtrace buffer is 00:13:07.120 --> 00:13:09.079 there's this library called PyDumpling 00:13:09.080 --> 00:13:14.659 which can serialize a traceback and store it to a file. 00:13:14.660 --> 00:13:17.859 So you can use PyDumpling with your applications running in 00:13:17.860 --> 00:13:21.239 production to serialize a traceback 00:13:21.240 --> 00:13:24.899 whenever they have an exception and save it to a file. 00:13:24.900 --> 00:13:28.599 Then you can transfer the file locally 00:13:28.600 --> 00:13:38.859 and load it into your local Emacs with slime-py-load-pydumpling. 00:13:38.860 --> 00:13:41.839 This will load the same backtrace buffer, 00:13:41.840 --> 00:13:44.559 and you see all the same local variables 00:13:44.560 --> 00:13:45.759 at the time of the exception. 00:13:45.760 --> 00:13:48.199 You can inspect them and get a REPL 00:13:48.200 --> 00:13:50.999 in the context of the stack frame. 00:13:51.000 --> 00:13:54.199 Well, this will only work for variables 00:13:54.200 --> 00:13:57.619 that can be serialized with pickle. 00:13:57.620 --> 00:13:59.519 Or actually, the library uses dill, 00:13:59.520 --> 00:14:03.039 which can serialize a bit more than pickle can. 00:14:03.040 --> 00:14:10.200 But yeah so this can help you inspect and debug errors 00:14:10.201 --> 00:14:12.880 for applications running in production remotely 00:14:12.881 --> 00:14:20.059 that you don't want to have SLIME connected to 24-7. NOTE Documentation browser 00:14:20.060 --> 00:14:24.859 Next up, let's look at the documentation browser. 00:14:24.860 --> 00:14:29.919 We can bring up documentation for any module, 00:14:29.920 --> 00:14:33.079 and all this information is generated 00:14:33.080 --> 00:14:34.999 from runtime introspection, 00:14:35.000 --> 00:14:37.079 from the doc strings for the module 00:14:37.080 --> 00:14:39.159 and the classes and so on. 00:14:39.160 --> 00:14:41.879 So you won't see documentation for libraries 00:14:41.880 --> 00:14:43.159 that you don't have actually loaded 00:14:43.160 --> 00:14:45.939 into your running Python process. 00:14:45.940 --> 00:14:50.119 Then you can go browse to classes. 00:14:50.120 --> 00:14:54.719 It'll show all the attributes, their methods, and so on. 00:14:54.720 --> 00:14:57.239 By each method to the right, it will show 00:14:57.240 --> 00:15:02.599 the base class where the method was originally inherited from. 00:15:02.600 --> 00:15:09.079 You can also bring up a screen with all the Python packages 00:15:09.080 --> 00:15:14.439 that are installed, and browse that with imenu, 00:15:14.440 --> 00:15:20.359 and bring up information on any package and so on. NOTE Thread view 00:15:20.360 --> 00:15:28.499 Next up, let's take a look at the thread view. 00:15:28.500 --> 00:15:31.839 So let's run this and then bring up the thread view 00:15:31.840 --> 00:15:35.559 and this will show information on all running threads. 00:15:35.560 --> 00:15:38.799 You can configure it to refresh after a given interval, 00:15:38.800 --> 00:15:41.959 like every second, but I don't have that set up right now, 00:15:41.960 --> 00:15:45.659 so I have to manually refresh it. 00:15:45.660 --> 00:15:47.639 Probably the most useful thing is that 00:15:47.640 --> 00:15:49.739 you can bring up a backtrace for any thread 00:15:49.740 --> 00:15:51.759 which won't pause the thread or anything, 00:15:51.760 --> 00:15:53.879 but will just give you the call stack 00:15:53.880 --> 00:15:55.879 at the time you requested the backtrace. 00:15:55.880 --> 00:15:59.199 You can again view the stack frames, local variables, 00:15:59.200 --> 00:16:04.139 open a REPL in the context of the thread, and so on. 00:16:04.140 --> 00:16:07.839 There's also a viewer for async tasks, 00:16:07.840 --> 00:16:09.999 but I'm not going to demo that right now, 00:16:10.000 --> 00:16:14.159 because for that to work, you have to start swanky-python 00:16:14.160 --> 00:16:16.599 after the async event loop has started, 00:16:16.600 --> 00:16:18.519 from within the same thread. 00:16:18.520 --> 00:16:20.279 If you go to the project readme, 00:16:20.280 --> 00:16:23.919 there's a demo of how to use the async task viewer 00:16:23.920 --> 00:16:27.439 with a fastapi project. NOTE Tracing functions 00:16:27.440 --> 00:16:33.879 Next up, let's look at tracing functions. 00:16:33.880 --> 00:16:36.279 So here we got some random error, 00:16:36.280 --> 00:16:39.879 because this is still very much a work in progress. 00:16:39.880 --> 00:16:42.359 But it looks like it executed 00:16:42.360 --> 00:16:43.199 correctly this time. 00:16:43.200 --> 00:16:47.565 So now let's mark the fibonacci function 00:16:47.566 --> 00:16:50.239 for tracing and execute it. 00:16:50.240 --> 00:16:56.079 We can see, every time the function is called, 00:16:56.080 --> 00:16:58.239 all its arguments and return values. 00:16:58.240 --> 00:17:02.899 Again, there are presentations that we can inspect and so on. 00:17:02.900 --> 00:17:06.079 But let's inspect a more complex object, like a file object. 00:17:06.080 --> 00:17:11.339 If we trace the count_lines function and run that code, 00:17:11.340 --> 00:17:15.319 then we can inspect the file it was passed, or the file object. 00:17:15.320 --> 00:17:21.039 One pitfall is that in Python, objects are mutable. 00:17:21.040 --> 00:17:25.559 So in the trace buffer, the string representation 00:17:25.560 --> 00:17:27.879 that's printed is the string representation 00:17:27.880 --> 00:17:31.219 at the time it was passed to the function. 00:17:31.220 --> 00:17:32.639 But when we go to inspect it, 00:17:32.640 --> 00:17:34.919 we're inspecting the object as it is right now, 00:17:34.920 --> 00:17:37.639 which can be different than it was at the time 00:17:37.640 --> 00:17:41.559 the function saw it. So for this file object, for example, 00:17:41.560 --> 00:17:44.279 it's closed now, when it was open at the time 00:17:44.280 --> 00:17:47.799 the function used it. NOTE AI integrations 00:17:47.800 --> 00:17:50.479 Next up, let's look at AI integrations. 00:17:50.480 --> 00:17:54.519 So if you're used to SLIME with Common Lisp, 00:17:54.520 --> 00:18:09.479 Emacs actually has a built-in AI that can help with the transition. 00:18:09.480 --> 00:18:14.559 So it's just a joke, I actually really like Python. 00:18:14.560 --> 00:18:18.119 And for more serious AI integrations, 00:18:18.120 --> 00:18:19.959 I have some ideas for the future 00:18:19.960 --> 00:18:21.919 but I haven't implemented anything yet. 00:18:21.920 --> 00:18:27.319 I think right now, people are mostly passing source code to LLMs 00:18:27.320 --> 00:18:32.679 but since we're embedded in the Python process at runtime, 00:18:32.680 --> 00:18:35.639 we have a lot of more information available, 00:18:35.640 --> 00:18:39.439 like maybe we can trace all calls to functions, 00:18:39.440 --> 00:18:41.799 and when we have a bug, 00:18:41.800 --> 00:18:46.479 we can feed the trace to the LLM, 00:18:46.480 --> 00:18:48.719 and the LLM can point out maybe 00:18:48.720 --> 00:18:51.959 when this function was called with these arguments, 00:18:51.960 --> 00:18:53.879 its return value doesn't make sense, 00:18:53.880 --> 00:18:55.679 so maybe that's the root cause of your bug. 00:18:55.680 --> 00:19:02.359 If you have any ideas of potential LLM or AI integrations, 00:19:02.360 --> 00:19:05.999 let me know. I'm happy to discuss. NOTE LSP-type features 00:19:06.000 --> 00:19:09.919 Next up, let's look at standard LSP-type features. 00:19:09.920 --> 00:19:14.439 So we've got completions. It's fuzzy completions right now, 00:19:14.440 --> 00:19:16.319 so it's showing everything with a PR in the name. 00:19:16.320 --> 00:19:21.779 We can bring up documentation for each one. 00:19:21.780 --> 00:19:26.759 When we start calling a method in the minibuffer at the bottom 00:19:26.760 --> 00:19:28.859 it'll show the signature. 00:19:28.860 --> 00:19:33.719 There's some refactoring available. 00:19:33.720 --> 00:19:37.399 We can extract a function or variable, 00:19:37.400 --> 00:19:39.499 or rename something, 00:19:39.500 --> 00:19:42.919 like, let's rename fib to fib2, 00:19:42.920 --> 00:19:47.479 and it will rename all the uses of it. 00:19:47.480 --> 00:19:49.759 All these features are based on Jedi, 00:19:49.760 --> 00:19:55.399 which is the Python library used by IPython. 00:19:55.400 --> 00:19:56.999 But as it is right now, 00:19:57.000 --> 00:20:02.039 if you want the most complete Python development experience 00:20:02.040 --> 00:20:05.579 in Emacs, I'd probably recommend using LSP 00:20:05.580 --> 00:20:10.439 for everything LSP can do, and then just using swanky-python 00:20:10.440 --> 00:20:13.679 for the object inspector and backtrace buffer, 00:20:13.680 --> 00:20:15.359 and the interactive features it has 00:20:15.360 --> 00:20:18.031 that an LSP can't provide. NOTE Wrapping up 00:20:18.032 --> 00:20:23.339 And that's it really. 00:20:23.340 --> 00:20:25.865 Shortly we'll have questions and answers 00:20:25.866 --> 00:20:28.799 as part of EmacsConf, and later on, 00:20:28.800 --> 00:20:31.199 if you have any questions, ideas, or issues 00:20:31.200 --> 00:20:34.639 feel free to reach out over email 00:20:34.640 --> 00:20:37.999 or create an issue on the repository. 00:20:38.000 --> 00:20:39.331 I should probably warn you, 00:20:39.332 --> 00:20:41.119 if you want to try out the project: 00:20:41.120 --> 00:20:45.279 so far I'm probably the only user of it 00:20:45.280 --> 00:20:48.279 and I've only tested it on my own Emacs setup, 00:20:48.280 --> 00:20:50.839 so it's quite likely you'll run into issues 00:20:50.840 --> 00:20:53.479 trying to get it installed and working. 00:20:53.480 --> 00:20:56.119 But if you do run into problems, please reach out, 00:20:56.120 --> 00:20:59.279 let me know. I'm happy to help and try and fix them. 00:20:59.280 --> 00:21:03.640 So that's it. Thanks for listening.