|
| 1 | +MEP11: Third-party dependencies |
| 2 | +=============================== |
| 3 | + |
| 4 | +.. contents:: |
| 5 | + :local: |
| 6 | + |
| 7 | +This MEP attempts to improve the way in which third-party dependencies |
| 8 | +in matplotlib are handled. |
| 9 | + |
| 10 | +Status |
| 11 | +------ |
| 12 | + |
| 13 | +**Completed** -- needs to be merged |
| 14 | + |
| 15 | +Branches and Pull requests |
| 16 | +-------------------------- |
| 17 | + |
| 18 | +#1157: Use automatic dependency resolution |
| 19 | + |
| 20 | +#1290: Debundle pyparsing |
| 21 | + |
| 22 | +#1261: Update six to 1.2 |
| 23 | + |
| 24 | +Abstract |
| 25 | +-------- |
| 26 | + |
| 27 | +One of the goals of matplotlib has been to keep it as easy to install |
| 28 | +as possible. To that end, some third-party dependencies are included |
| 29 | +in the source tree and, under certain circumstances, installed |
| 30 | +alongside matplotlib. This MEP aims to resolve some problems with |
| 31 | +that approach, bring some consistency, while continuing to make |
| 32 | +installation convenient. |
| 33 | + |
| 34 | +At the time that was initially done, `setuptools`, `easy_install` and |
| 35 | +`PyPI` were not mature enough to be relied on. However, at present, |
| 36 | +we should be able to safely leverage the "modern" versions of those |
| 37 | +tools, `distribute` and `pip`. |
| 38 | + |
| 39 | +While matplotlib has dependencies on both Python libraries and C/C++ |
| 40 | +libraries, this MEP addresses only the Python libraries so as to not |
| 41 | +confuse the issue. C libraries represent a larger and mostly |
| 42 | +orthogonal set of problems. |
| 43 | + |
| 44 | +Detailed description |
| 45 | +-------------------- |
| 46 | + |
| 47 | +matplotlib depends on the following third-party Python libraries: |
| 48 | + |
| 49 | + - Numpy |
| 50 | + - dateutil (pure Python) |
| 51 | + - pytz (pure Python) |
| 52 | + - six -- required by dateutil (pure Python) |
| 53 | + - pyparsing (pure Python) |
| 54 | + - PIL (optional) |
| 55 | + - GUI frameworks: pygtk, gobject, tkinter, PySide, PyQt4, wx (all |
| 56 | + optional, but one is required for an interactive GUI) |
| 57 | + |
| 58 | +Current behavior |
| 59 | +```````````````` |
| 60 | + |
| 61 | +When installing from source, a `git` checkout or `pip`: |
| 62 | + |
| 63 | + - `setup.py` attempts to `import numpy`. If this fails, the |
| 64 | + installation fails. |
| 65 | + |
| 66 | + - For each of `dateutil`, `pytz` and `six`, `setup.py` attempts to |
| 67 | + import them (from the top-level namespace). If that fails, |
| 68 | + matplotlib installs its local copy of the library into the |
| 69 | + top-level namespace. |
| 70 | + |
| 71 | + - `pyparsing` is always installed inside of the matplotlib |
| 72 | + namespace. |
| 73 | + |
| 74 | +This behavior is most surprising when used with `pip`, because no |
| 75 | +`pip` dependency resolution is performed, even though it is likely to |
| 76 | +work for all of these packages. |
| 77 | + |
| 78 | +The fact that `pyparsing` is installed in the matplotlib namespace has |
| 79 | +reportedly (#1290) confused some users into thinking it is a |
| 80 | +matplotlib-related module and import it from there rather than the |
| 81 | +top-level. |
| 82 | + |
| 83 | +When installing using the Windows installer, `dateutil`, `pytz` and |
| 84 | +`six` are installed at the top-level *always*, potentially overwriting |
| 85 | +already installed copies of those libraries. |
| 86 | + |
| 87 | +TODO: Describe behavior with the OS-X installer. |
| 88 | + |
| 89 | +When installing using a package manager (Debian, RedHat, MacPorts |
| 90 | +etc.), this behavior actually does the right thing, and there are no |
| 91 | +special patches in the matplotlib packages to deal with the fact that |
| 92 | +we handle `dateutil`, `pytz` and `six` in this way. However, care |
| 93 | +should be taken that whatever approach we move to continues to work in |
| 94 | +that context. |
| 95 | + |
| 96 | +Maintaining these packages in the matplotlib tree and making sure they |
| 97 | +are up-to-date is a maintenance burden. Advanced new features that |
| 98 | +may require a third-party pure Python library have a higher barrier to |
| 99 | +inclusion because of this burden. |
| 100 | + |
| 101 | + |
| 102 | +Desired behavior |
| 103 | +```````````````` |
| 104 | + |
| 105 | +Third-party dependencies are downloaded and installed from their |
| 106 | +canonical locations by leveraging `pip`, `distribute` and `PyPI`. |
| 107 | + |
| 108 | +`dateutil`, `pytz`, and `pyparsing` should be made into optional |
| 109 | +dependencies -- though obviously some features would fail if they |
| 110 | +aren't installed. This will allow the user to decide whether they |
| 111 | +want to bother installing a particular feature. |
| 112 | + |
| 113 | +Implementation |
| 114 | +-------------- |
| 115 | + |
| 116 | +For installing from source, and assuming the user has all of the |
| 117 | +C-level compilers and dependencies, this can be accomplished fairly |
| 118 | +easily using `distribute` and following the instructions `here |
| 119 | +<http://packages.python.org/distribute/>`_. The only anticipated |
| 120 | +change to the matplotlib library code will be to import `pyparsing` |
| 121 | +from the top-level namespace rather than from within matplotlib. Note |
| 122 | +that `distribute` will also allow us to remove the direct dependency |
| 123 | +on `six`, since it is, strictly speaking, only a direct dependency of |
| 124 | +`dateutil`. |
| 125 | + |
| 126 | +For binary installations, there are a number of alternatives (here |
| 127 | +ordered from best/hardest to worst/easiest): |
| 128 | + |
| 129 | + 1. The distutils wininst installer allows a post-install script to |
| 130 | + run. It might be possible to get this script to run `pip` to |
| 131 | + install the other dependencies. (See `this thread |
| 132 | + <http://grokbase.com/t/python/distutils-sig/109bdnfhp4/distutils-ann-setuptools-post-install-script-for-bdist-wininst>`_ |
| 133 | + for someone who has trod that ground before). |
| 134 | + |
| 135 | + 2. Continue to ship `dateutil`, `pytz`, `six` and `pyparsing` in |
| 136 | + our installer, but use the post-install-script to install them |
| 137 | + *only* if they can not already be found. |
| 138 | + |
| 139 | + 3. Move all of these packages inside a (new) `matplotlib.extern` |
| 140 | + namespace so it is clear for outside users that these are |
| 141 | + external packages. Add some conditional imports in the core |
| 142 | + matplotlib codebase so `dateutil` (at the top-level) is tried |
| 143 | + first, and failing that `matplotlib.extern.dateutil` is used. |
| 144 | + |
| 145 | +2 and 3 are undesirable as they still require maintaining copies of |
| 146 | +these packages in our tree -- and this is exacerbated by the fact that |
| 147 | +they are used less -- only in the binary installers. None of these 3 |
| 148 | +approaches address Numpy, which will still have to be manually |
| 149 | +installed using an installer. |
| 150 | + |
| 151 | +TODO: How does this relate to the Mac OS-X installer? |
| 152 | + |
| 153 | +Backward compatibility |
| 154 | +---------------------- |
| 155 | + |
| 156 | +At present, matplotlib can be installed from source on a machine |
| 157 | +without the third party dependencies and without an internet |
| 158 | +connection. After this change, an internet connection (and a working |
| 159 | +PyPI) will be required to install matplotlib for the first time. |
| 160 | +(Subsequent matplotlib updates or development work will run without |
| 161 | +accessing the network). |
| 162 | + |
| 163 | +Alternatives |
| 164 | +------------ |
| 165 | + |
| 166 | +Distributing binary `eggs` doesn't feel like a usable solution. That |
| 167 | +requires getting `easy_install` installed first, and Windows users |
| 168 | +generally prefer the well known `.exe` or `.msi` installer that works |
| 169 | +out of the box. |
0 commit comments