This is a mighty great example since there is so much variety there:
Looking at the current pip (19.2.2) setup.py we have these:
license=‘MIT’, ← this would be technically correct as a valid license expression
classifiers=[
…
“License :: OSI Approved :: MIT License”, ← this should trigger an informational warning that this is redundant (we could also be harsher)
But in reality you have many more licenses from the src/pip/_vendor
directory, beyond the primary MIT.
- appdirs: MIT
- distro: Apache-2.0
- ipaddress: Python-2.0
- pyparsing: MIT
- retrying: Apache-2.0
- six: MIT
- cachecontrol: Apache-2.0
- certifi: MPL-2.0
- chardet: LGPL-2.1-or-later
- colorama: BSD-3-Clause
- distlib: Python-2.0
- distlib/_backport/misc.py: MIT
- idna: BSD-3-Clause AND (Python-2.0 AND Unicode-DFS-2015)
- lockfile: MIT
- lockfile/pidlockfile.py: Python-2.0
- msgpack: Apache-2.0
- packaging: Apache-2.0 OR BSD-2-Clause
- pep517: MIT
- pep517/colorlog.py: Apache-2.0
- pkg_resources: MIT
- progress: ISC
- pytoml: MIT-0
- requests: Apache-2.0
- urlib3: MIT
- urllib3/packages/rfc3986: Apache-2.0
- webencodings: BSD-3-Clause
Therefore you have two options IMHO:
A) one keep only MIT
as an expression in the license metadata since you are already vendoring and including the licenses text of all these. This is in the spirit of keeping this simple. Since you include all texts and source code, you are complying with most if not all license conditions AFAIK and so would any of redistributors downstream.
B) provide a proper license
license expression joining them all (with an AND) and a license_files
list of all the license files that you are already including for full disclosures and details.
This expression would be either the full unsimplified expression:
MIT AND (MIT AND Apache-2.0 AND Python-2.0 AND MIT AND Apache-2.0 AND MIT AND Apache-2.0 AND MPL-2.0 AND LGPL-2.1-or-later AND BSD-3-Clause AND (Python-2.0 AND MIT) AND (BSD-3-Clause AND (Python-2.0 AND Unicode-DFS-2015)) AND (MIT AND Python-2.0) AND Apache-2.0 AND (Apache-2.0 OR BSD-2-Clause) AND (MIT AND Apache-2.0) AND MIT AND ISC AND MIT-0 AND Apache-2.0 AND (MIT AND Apache-2.0) AND BSD-3-Clause)
(I have used parenthesis here purely for “cosmetic effect” to group the subexpressions of each package together and put MIT as the left most one since this is the main one)
- or a simplified version:
MIT AND (Apache-2.0 AND BSD-3-Clause AND ISC AND LGPL-2.1-or-later AND MIT AND MIT-0 AND MPL-2.0 AND Python-2.0 AND Unicode-DFS-2015)
using still the extra MIT at the start to depict (strictly visually) that it is the main one. I have cheated for that and used this snippet to do a boolean simplification of the full long version:
$ pip install license-expression
$ python
>>> from license_expression import Licensing
>>> l = Licensing()
>>> expression = 'MIT AND (MIT AND Apache-2.0 AND Python-2.0 AND MIT AND Apache-2.0 AND MIT AND Apache-2.0 AND MPL-2.0 AND LGPL-2.1-or-later AND BSD-3-Clause AND (Python-2.0 AND MIT) AND (BSD-3-Clause AND (Python-2.0 AND Unicode-DFS-2015)) AND (MIT AND Python-2.0) AND Apache-2.0 AND (Apache-2.0 OR BSD-2-Clause) AND (MIT AND Apache-2.0) AND MIT AND ISC AND MIT-0 AND Apache-2.0 AND (MIT AND Apache-2.0) AND BSD-3-Clause)'
>>> parsed = l.parse(expression)
>>> parsed
AND(LicenseSymbol(u'MIT', is_exception=False), AND(LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False), LicenseSymbol(u'Python-2.0', is_exception=False), LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False), LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False), LicenseSymbol(u'MPL-2.0', is_exception=False), LicenseSymbol(u'LGPL-2.1-or-later', is_exception=False), LicenseSymbol(u'BSD-3-Clause', is_exception=False), AND(LicenseSymbol(u'Python-2.0', is_exception=False), LicenseSymbol(u'MIT', is_exception=False)), AND(LicenseSymbol(u'BSD-3-Clause', is_exception=False), AND(LicenseSymbol(u'Python-2.0', is_exception=False), LicenseSymbol(u'Unicode-DFS-2015', is_exception=False))), AND(LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Python-2.0', is_exception=False)), LicenseSymbol(u'Apache-2.0', is_exception=False), OR(LicenseSymbol(u'Apache-2.0', is_exception=False), LicenseSymbol(u'BSD-2-Clause', is_exception=False)), AND(LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False)), LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'ISC', is_exception=False), LicenseSymbol(u'MIT-0', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False), AND(LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'Apache-2.0', is_exception=False)), LicenseSymbol(u'BSD-3-Clause', is_exception=False)))
>>> parsed.simplify()
AND(LicenseSymbol(u'Apache-2.0', is_exception=False), LicenseSymbol(u'BSD-3-Clause', is_exception=False), LicenseSymbol(u'ISC', is_exception=False), LicenseSymbol(u'LGPL-2.1-or-later', is_exception=False), LicenseSymbol(u'MIT', is_exception=False), LicenseSymbol(u'MIT-0', is_exception=False), LicenseSymbol(u'MPL-2.0', is_exception=False), LicenseSymbol(u'Python-2.0', is_exception=False), LicenseSymbol(u'Unicode-DFS-2015', is_exception=False))
>>> str(parsed.simplify())
'Apache-2.0 AND BSD-3-Clause AND ISC AND LGPL-2.1-or-later AND MIT AND MIT-0 AND MPL-2.0 AND Python-2.0 AND Unicode-DFS-2015'