Monday, December 04, 2017

Creating extension to profile Python with PyVmMonitor from Visual Studio Code

Ok, so, the target here is doing a simple extension with Visual Studio Code which will help in profiling the current module using PyVmMonitor (http://www.pyvmmonitor.com/).

The extension will provide a command which should open a few options for the user on how he wants to do the profile (with yappi, cProfile or start without profiling but connected with the live sampling view).

I went with https://code.visualstudio.com/docs/extensions/yocode to bootstrap the extension, which gives a template with a command to run then renamed a bunch of things (such as the extension name, description, command name, etc).

Next was finding a way to ask the user for the options (to ask how the profile should be started). Searching for it revealed https://tstringer.github.io/nodejs/javascript/vscode/2015/12/14/input-and-output-vscode-ext.html, so, I went with creating the needed constants and going with vscode.window.showQuickPick (experimenting, undefined is returned if the user cancel the action, so, that needs to be taken into account too).

Now, after the user chooses how to start PyVmMonitor, the idea would be making any launch actually start in the chosen profile mode (which is how it works in PyDev).

After investigating a bit, I couldn't find out how to intercept an existing launch to modify the command line to add the needed parameters for profiling with PyVmMonitor, so, this integration will be a bit more limited than the one in PyDev as it will simply create a new terminal and call PyVmMonitor asking it to profile the currently opened module...

In the other integrations, it was done as a setting where the user selected that it wanted to profile any python launch from a given point onward as a toggle and then intercepted launches changing the command line given, so, for instance, it could intercept a unittest launch too, but in this case, it seems that there's currently no way to do that -- or some ineptitude on my part finding an actual API to do it ;)

Now, searching on the VSCode Python plugin, I found a "function execInTerminal", so, I based the launching in it (but not using its settings as I don't want to add a dependency on it for now, so, I just call `python` -- if that's wrong, as it opens a shell, the user is free to cancel that and correct the command line to use the appropriate python interpreter or change it as needed later on).

Ok, wrapping up: put the initial version of the code on https://github.com/fabioz/vscode-pyvmmonitor. Following https://code.visualstudio.com/docs/extensions/publish-extension did work out, so, there's a "Profile Python with PyVmMonitor" extension now ;).

Some notes I took during the process related to things I stumbled on or found awkard:
  • After publishing the first time and installing, the extension wasn't working because I wrongly put a dependency from npm in "devDependencies" and not in "dependencies" (the console in the developer tools helped in finding out that the dependency wasn't being loaded after the extension was installed).
  • When a dependency is added/removed, npm install needs to be called again, it's not automatic.
  • When uploading the extension I had the (common) error of not generating a token for "all" ;)
  • Apparently there's a "String" and a "string" in TypeScript (or at least within the dependencies when editing VSCode).
  • The whole launching on VSCode seems a bit limited/ad-hoc right now (for instance, .launch files create actual launchers which can be debugged but the python extension completely bypasses that by doing a launch in terminal for the current file -- probably because it's a bit of a pain creating that .launch file) -- I guess this reflects how young VSCode is... on the other hand, it really seems it built upon previous experience as the commands and bindings seems to have evolved directly to a good design (Eclipse painfully iterated over several designs on its command API).
  • Extensions seem to be limited by design. I guess this is good and bad at the same time... good that extensions should never slow down the editor, but bad because they are not able to do something which is not in the platform itself to start with -- for instance, I really missed a good unittest UI when using it... there are actually many other things I missed from PyDev, although I guess this is probably a reflect on how young the platform is (and it does seem to be shaping up fast).