This PR fixes #675.
It has been tested on Linux (Ubuntu 18.04) but not Windows, OSX or Raspberry Pi. Please give feedback from testing in these environments.
What does it do?
This is the simplest possible third party package manager for a beginners' editor. Until now we have bundled a bunch of "third party" modules with Mu in the official installers, thus bloating Mu's size. Furthermore, our bundled modules go out of date and/or miss some important packages for folks. This new functionality allows users to simply specify packages to be installed from PyPI. It also allows users to remove packages.
It is accessed via the "admin" dialog (accessed via the cog on the bottom right of the UI) and is one of the tabs found therein. The following GIF demonstrates it in action:
The user simply ensures the list of module names (one per line) reflects their requirements. To remove a module from the list, just remove its line. Python's pip
command (which does the heavy lifting under the hood) will, of course, install dependencies as required. To keep things simple (this is a beginners' editor!) the notion of version number is ignored, and the latest version will be installed by default. Ergo, if a user needs to update a package, they should remove and re-install it.
Currently, there is no attempt to handle conflicts between pre-packaged (in the installer) modules or the same module installed via this method. My hunch is to remove these pre-installed modules in favour of this mechanism. I would love to hear thoughts on this from folks!
Packages installed in this way are available in both scripts run or debugged in Python 3 mode, or from within the Python 3 REPL (iPython shell).
How Does it Work?
There were several ways to skin this cat, and I've gone for the simplest I can think of.
- The new tab for third party packages is added to the admin dialog. If, when the dialog is closed via "OK", there is a change in package state, then a new modal dialog launches to provide visibility of the package syncing process.
- This new package related dialog simply contains a text area into which is piped information from
pip
and other functionality.
- The recommended way to use pip is by launching it in a subprocess. The
pip
developers will not guarantee the internal API of the pip
module. This is why things work the way they do: new packages are added to a list. The first new package is popped from the list and installed via pip
in a subprocess. When the subprocess completes, if there are any more candidate packages to install, the process is repeated.
- The
--target
flag is used to specify an OS specific writeable directory into which these packages will be installed. This directory is added to the Python path when running or debugging Python 3 scripts or using the Python 3 REPL.
- Sadly, the
pip
command doesn't allow for targetting a "package directory" from which to remove packages. Ergo, Mu uses the list of packages that have been removed in the admin dialog to discover the metadata for them in the directory Mu uses for such packages. Happily, the metadata contains a list of all files related to each package. Mu simply iterates over these, deletes them and deletes any parent directories related to the module to be removed.
That's it! All feedback most welcome!
cc/@asweigart