|
| 1 | +.. _licensing-examples-and-user-scenarios: |
| 2 | + |
| 3 | + |
| 4 | +===================================== |
| 5 | +Licensing examples and user scenarios |
| 6 | +===================================== |
| 7 | + |
| 8 | + |
| 9 | +:pep:`639` has specified the way to declare a project's license and paths to |
| 10 | +license files and other legally required information. |
| 11 | +This document aims to provide clear guidance how to migrate from the legacy |
| 12 | +to the standardized way of declaring licenses. |
| 13 | + |
| 14 | + |
| 15 | +Licensing Examples |
| 16 | +================== |
| 17 | + |
| 18 | +.. _licensing-example-basic: |
| 19 | + |
| 20 | +Basic example |
| 21 | +------------- |
| 22 | + |
| 23 | +The Setuptools project itself, as of `version 75.6.0 <setuptools7560_>`__, |
| 24 | +does not use the ``License`` field in its own project source metadata. |
| 25 | +Further, it no longer explicitly specifies ``license_file``/``license_files`` |
| 26 | +as it did previously, since Setuptools relies on its own automatic |
| 27 | +inclusion of license-related files matching common patterns, |
| 28 | +such as the :file:`LICENSE` file it uses. |
| 29 | + |
| 30 | +It includes the following license-related metadata in its |
| 31 | +:file:`pyproject.toml`: |
| 32 | + |
| 33 | +.. code-block:: toml |
| 34 | +
|
| 35 | + [project] |
| 36 | + classifiers = [ |
| 37 | + "License :: OSI Approved :: MIT License" |
| 38 | + ] |
| 39 | +
|
| 40 | +The simplest migration to PEP 639 would consist of using this instead: |
| 41 | + |
| 42 | +.. code-block:: toml |
| 43 | +
|
| 44 | + [project] |
| 45 | + license = "MIT" |
| 46 | +
|
| 47 | +Or, if the project used :file:`setup.cfg`, in its ``[metadata]`` table: |
| 48 | + |
| 49 | +.. code-block:: ini |
| 50 | +
|
| 51 | + [metadata] |
| 52 | + license = MIT |
| 53 | +
|
| 54 | +The output Core Metadata for the distribution packages would then be: |
| 55 | + |
| 56 | +.. code-block:: email |
| 57 | +
|
| 58 | + License-Expression: MIT |
| 59 | + License-File: LICENSE |
| 60 | +
|
| 61 | +The :file:`LICENSE` file would be stored at :file:`/setuptools-{VERSION}/LICENSE` |
| 62 | +in the sdist and :file:`/setuptools-{VERSION}.dist-info/licenses/LICENSE` |
| 63 | +in the wheel, and unpacked from there into the site directory (e.g. |
| 64 | +:file:`site-packages/`) on installation; :file:`/` is the root of the respective archive |
| 65 | +and ``{VERSION}`` the version of the Setuptools release in the Core Metadata. |
| 66 | + |
| 67 | + |
| 68 | +.. _licensing-example-advanced: |
| 69 | + |
| 70 | +Advanced example |
| 71 | +---------------- |
| 72 | + |
| 73 | +Suppose Setuptools were to include the licenses of the third-party projects |
| 74 | +that are vendored in the :file:`setuptools/_vendor/` and :file:`pkg_resources/_vendor/` |
| 75 | +directories; specifically: |
| 76 | + |
| 77 | +.. code-block:: text |
| 78 | +
|
| 79 | + packaging==21.2 |
| 80 | + pyparsing==2.2.1 |
| 81 | + ordered-set==3.1.1 |
| 82 | + more_itertools==8.8.0 |
| 83 | +
|
| 84 | +The license expressions for these projects are: |
| 85 | + |
| 86 | +.. code-block:: text |
| 87 | +
|
| 88 | + packaging: Apache-2.0 OR BSD-2-Clause |
| 89 | + pyparsing: MIT |
| 90 | + ordered-set: MIT |
| 91 | + more_itertools: MIT |
| 92 | +
|
| 93 | +A comprehensive license expression covering both Setuptools |
| 94 | +proper and its vendored dependencies would contain these metadata, |
| 95 | +combining all the license expressions into one. Such an expression might be: |
| 96 | + |
| 97 | +.. code-block:: text |
| 98 | +
|
| 99 | + MIT AND (Apache-2.0 OR BSD-2-Clause) |
| 100 | +
|
| 101 | +In addition, per the requirements of the licenses, the relevant license files |
| 102 | +must be included in the package. Suppose the :file:`LICENSE` file contains the text |
| 103 | +of the MIT license and the copyrights used by Setuptools, ``pyparsing``, |
| 104 | +``more_itertools`` and ``ordered-set``; and the :file:`LICENSE*` files in the |
| 105 | +:file:`setuptools/_vendor/packaging/` directory contain the Apache 2.0 and |
| 106 | +2-clause BSD license text, and the Packaging copyright statement and |
| 107 | +`license choice notice <packaginglicense_>`__. |
| 108 | + |
| 109 | +Specifically, we assume the license files are located at the following |
| 110 | +paths in the project source tree (relative to the project root and |
| 111 | +:file:`pyproject.toml`): |
| 112 | + |
| 113 | +.. code-block:: text |
| 114 | +
|
| 115 | + LICENSE |
| 116 | + setuptools/_vendor/packaging/LICENSE |
| 117 | + setuptools/_vendor/packaging/LICENSE.APACHE |
| 118 | + setuptools/_vendor/packaging/LICENSE.BSD |
| 119 | +
|
| 120 | +Putting it all together, our :file:`pyproject.toml` would be: |
| 121 | + |
| 122 | +.. code-block:: toml |
| 123 | +
|
| 124 | + [project] |
| 125 | + license = "MIT AND (Apache-2.0 OR BSD-2-Clause)" |
| 126 | + license-files = [ |
| 127 | + "LICENSE*", |
| 128 | + "setuptools/_vendor/LICENSE*", |
| 129 | + ] |
| 130 | +
|
| 131 | +Or alternatively, the license files can be specified explicitly (paths will be |
| 132 | +interpreted as glob patterns): |
| 133 | + |
| 134 | +.. code-block:: toml |
| 135 | +
|
| 136 | + [project] |
| 137 | + license = "MIT AND (Apache-2.0 OR BSD-2-Clause)" |
| 138 | + license-files = [ |
| 139 | + "LICENSE", |
| 140 | + "setuptools/_vendor/LICENSE", |
| 141 | + "setuptools/_vendor/LICENSE.APACHE", |
| 142 | + "setuptools/_vendor/LICENSE.BSD", |
| 143 | + ] |
| 144 | +
|
| 145 | +If our project used :file:`setup.cfg`, we could define this in : |
| 146 | + |
| 147 | +.. code-block:: ini |
| 148 | +
|
| 149 | + [metadata] |
| 150 | + license = MIT AND (Apache-2.0 OR BSD-2-Clause) |
| 151 | + license_files = |
| 152 | + LICENSE |
| 153 | + setuptools/_vendor/packaging/LICENSE |
| 154 | + setuptools/_vendor/packaging/LICENSE.APACHE |
| 155 | + setuptools/_vendor/packaging/LICENSE.BSD |
| 156 | +
|
| 157 | +With either approach, the output Core Metadata in the distribution |
| 158 | +would be: |
| 159 | + |
| 160 | +.. code-block:: email |
| 161 | +
|
| 162 | + License-Expression: MIT AND (Apache-2.0 OR BSD-2-Clause) |
| 163 | + License-File: LICENSE |
| 164 | + License-File: setuptools/_vendor/packaging/LICENSE |
| 165 | + License-File: setuptools/_vendor/packaging/LICENSE.APACHE |
| 166 | + License-File: setuptools/_vendor/packaging/LICENSE.BSD |
| 167 | +
|
| 168 | +In the resulting sdist, with :file:`/` as the root of the archive and ``{VERSION}`` |
| 169 | +the version of the Setuptools release specified in the Core Metadata, |
| 170 | +the license files would be located at the paths: |
| 171 | + |
| 172 | +.. code-block:: text |
| 173 | +
|
| 174 | + /setuptools-{VERSION}/LICENSE |
| 175 | + /setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE |
| 176 | + /setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.APACHE |
| 177 | + /setuptools-{VERSION}/setuptools/_vendor/packaging/LICENSE.BSD |
| 178 | +
|
| 179 | +In the built wheel, with :file:`/` being the root of the archive and |
| 180 | +``{VERSION}`` as the previous, the license files would be stored at: |
| 181 | + |
| 182 | +.. code-block:: text |
| 183 | +
|
| 184 | + /setuptools-{VERSION}.dist-info/licenses/LICENSE |
| 185 | + /setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE |
| 186 | + /setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE |
| 187 | + /setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD |
| 188 | +
|
| 189 | +Finally, in the installed project, with :file:`site-packages/` being the site dir |
| 190 | +and ``{VERSION}`` as the previous, the license files would be installed to: |
| 191 | + |
| 192 | +.. code-block:: text |
| 193 | +
|
| 194 | + site-packages/setuptools-{VERSION}.dist-info/licenses/LICENSE |
| 195 | + site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE |
| 196 | + site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE |
| 197 | + site-packages/setuptools-{VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD |
| 198 | +
|
| 199 | +
|
| 200 | +Expression examples |
| 201 | +''''''''''''''''''' |
| 202 | + |
| 203 | +Some additional examples of valid ``License-Expression`` values: |
| 204 | + |
| 205 | +.. code-block:: email |
| 206 | +
|
| 207 | + License-Expression: MIT |
| 208 | + License-Expression: BSD-3-Clause |
| 209 | + License-Expression: MIT AND (Apache-2.0 OR BSD-2-Clause) |
| 210 | + License-Expression: MIT OR GPL-2.0-or-later OR (FSFUL AND BSD-2-Clause) |
| 211 | + License-Expression: GPL-3.0-only WITH Classpath-Exception-2.0 OR BSD-3-Clause |
| 212 | + License-Expression: LicenseRef-Public-Domain OR CC0-1.0 OR Unlicense |
| 213 | + License-Expression: LicenseRef-Proprietary |
| 214 | + License-Expression: LicenseRef-Custom-License |
| 215 | +
|
| 216 | +
|
| 217 | +User Scenarios |
| 218 | +============== |
| 219 | + |
| 220 | +The following covers the range of common use cases from a user perspective, |
| 221 | +providing guidance for each. Do note that the following |
| 222 | +should **not** be considered legal advice, and readers should consult a |
| 223 | +licensed legal practitioner in their jurisdiction if they are unsure about |
| 224 | +the specifics for their situation. |
| 225 | + |
| 226 | + |
| 227 | +I have a private package that won't be distributed |
| 228 | +-------------------------------------------------- |
| 229 | + |
| 230 | +If your package isn't shared publicly, i.e. outside your company, |
| 231 | +organization or household, it *usually* isn't strictly necessary to include |
| 232 | +a formal license, so you wouldn't necessarily have to do anything extra here. |
| 233 | + |
| 234 | +However, it is still a good idea to include ``LicenseRef-Proprietary`` |
| 235 | +as a license expression in your package configuration, and/or a |
| 236 | +copyright statement and any legal notices in a :file:`LICENSE.txt` file |
| 237 | +in the root of your project directory, which will be automatically |
| 238 | +included by packaging tools. |
| 239 | + |
| 240 | + |
| 241 | +I just want to share my own work without legal restrictions |
| 242 | +----------------------------------------------------------- |
| 243 | + |
| 244 | +While you aren't required to include a license, if you don't, no one has |
| 245 | +`any permission to download, use or improve your work <dontchoosealicense_>`__, |
| 246 | +so that's probably the *opposite* of what you actually want. |
| 247 | +The `MIT license <chooseamitlicense_>`__ is a great choice instead, as it's simple, |
| 248 | +widely used and allows anyone to do whatever they want with your work |
| 249 | +(other than sue you, which you probably also don't want). |
| 250 | + |
| 251 | +To apply it, just paste `the text <chooseamitlicense_>`__ into a file named |
| 252 | +:file:`LICENSE.txt` at the root of your repo, and add the year and your name to |
| 253 | +the copyright line. Then, just add ``license = "MIT"`` under |
| 254 | +``[project]`` in your :file:`pyproject.toml` if your packaging tool supports it, |
| 255 | +or in its config file/section. You're done! |
| 256 | + |
| 257 | + |
| 258 | +I want to distribute my project under a specific license |
| 259 | +-------------------------------------------------------- |
| 260 | + |
| 261 | +To use a particular license, simply paste its text into a :file:`LICENSE.txt` |
| 262 | +file at the root of your repo, if you don't have it in a file starting with |
| 263 | +:file:`LICENSE` or :file:`COPYING` already, and add |
| 264 | +``license = "LICENSE-ID"`` under ``[project]`` in your |
| 265 | +:file:`pyproject.toml` if your packaging tool supports it, or else in its |
| 266 | +config file. You can find the ``LICENSE-ID`` |
| 267 | +and copyable license text on sites like |
| 268 | +`ChooseALicense <choosealicenselist_>`__ or `SPDX <spdxlist_>`__. |
| 269 | + |
| 270 | +Many popular code hosts, project templates and packaging tools can add the |
| 271 | +license file for you, and may support the expression as well in the future. |
| 272 | + |
| 273 | + |
| 274 | +I maintain an existing package that's already licensed |
| 275 | +------------------------------------------------------ |
| 276 | + |
| 277 | +If you already have license files and metadata in your project, you |
| 278 | +should only need to make a couple of tweaks to take advantage of the new |
| 279 | +functionality. |
| 280 | + |
| 281 | +In your project config file, enter your license expression under |
| 282 | +``license`` (``[project]`` table in :file:`pyproject.toml`), |
| 283 | +or the equivalent for your packaging tool, |
| 284 | +and make sure to remove any legacy ``license`` table subkeys or |
| 285 | +``License ::`` classifiers. Your existing ``license`` value may already |
| 286 | +be valid as one (e.g. ``MIT``, ``Apache-2.0 OR BSD-2-Clause``, etc); |
| 287 | +otherwise, check the `SPDX license list <spdxlist_>`__ for the identifier |
| 288 | +that matches the license used in your project. |
| 289 | + |
| 290 | +Make sure to list your license files under ``license-files`` |
| 291 | +under ``[project]`` in :file:`pyproject.toml` |
| 292 | +or else in your tool's configuration file. |
| 293 | + |
| 294 | +See the :ref:`licensing-example-basic` for a simple but complete real-world demo |
| 295 | +of how this works in practice. |
| 296 | +See also the best-effort guidance on how to translate license classifiers |
| 297 | +into license expression provided by the :pep:`639` authors: |
| 298 | +`Mapping License Classifiers to SPDX Identifiers <mappingclassifierstospdx_>`__. |
| 299 | +Packaging tools may support automatically converting legacy licensing |
| 300 | +metadata; check your tool's documentation for more information. |
| 301 | + |
| 302 | + |
| 303 | +My package includes other code under different licenses |
| 304 | +------------------------------------------------------- |
| 305 | + |
| 306 | +If your project includes code from others covered by different licenses, |
| 307 | +such as vendored dependencies or files copied from other open source |
| 308 | +software, you can construct a license expression |
| 309 | +to describe the licenses involved and the relationship |
| 310 | +between them. |
| 311 | + |
| 312 | +In short, ``License-1 AND License-2`` mean that *both* licenses apply |
| 313 | +to your project, or parts of it (for example, you included a file |
| 314 | +under another license), and ``License-1 OR License-2`` means that |
| 315 | +*either* of the licenses can be used, at the user's option (for example, |
| 316 | +you want to allow users a choice of multiple licenses). You can use |
| 317 | +parenthesis (``()``) for grouping to form expressions that cover even the most |
| 318 | +complex situations. |
| 319 | + |
| 320 | +In your project config file, enter your license expression under |
| 321 | +``license`` (``[project]`` table of :file:`pyproject.toml`), |
| 322 | +or the equivalent for your packaging tool, |
| 323 | +and make sure to remove any legacy ``license`` table subkeys |
| 324 | +or ``License ::`` classifiers. |
| 325 | + |
| 326 | +Also, make sure you add the full license text of all the licenses as files |
| 327 | +somewhere in your project repository. List the |
| 328 | +relative path or glob patterns to each of them under ``license-files`` |
| 329 | +under ``[project]`` in :file:`pyproject.toml` |
| 330 | +(if your tool supports it), or else in your tool's configuration file. |
| 331 | + |
| 332 | +As an example, if your project was licensed MIT but incorporated |
| 333 | +a vendored dependency (say, ``packaging``) that was licensed under |
| 334 | +either Apache 2.0 or the 2-clause BSD, your license expression would |
| 335 | +be ``MIT AND (Apache-2.0 OR BSD-2-Clause)``. You might have a |
| 336 | +:file:`LICENSE.txt` in your repo root, and a :file:`LICENSE-APACHE.txt` and |
| 337 | +:file:`LICENSE-BSD.txt` in the :file:`_vendor/` subdirectory, so to include |
| 338 | +all of them, you'd specify ``["LICENSE.txt", "_vendor/packaging/LICENSE*"]`` |
| 339 | +as glob patterns, or |
| 340 | +``["LICENSE.txt", "_vendor/LICENSE-APACHE.txt", "_vendor/LICENSE-BSD.txt"]`` |
| 341 | +as literal file paths. |
| 342 | + |
| 343 | +See a fully worked out :ref:`licensing-example-advanced` for an end-to-end |
| 344 | +application of this to a real-world complex project, with many technical |
| 345 | +details, and consult a `tutorial <spdxtutorial_>`__ for more help and examples |
| 346 | +using SPDX identifiers and expressions. |
| 347 | + |
| 348 | + |
| 349 | +.. _chooseamitlicense: https://choosealicense.com/licenses/mit/ |
| 350 | +.. _choosealicenselist: https://choosealicense.com/licenses/ |
| 351 | +.. _dontchoosealicense: https://choosealicense.com/no-permission/ |
| 352 | +.. _mappingclassifierstospdx: https://peps.python.org/pep-0639/appendix-mapping-classifiers/ |
| 353 | +.. _packaginglicense: https://github.com/pypa/packaging/blob/21.2/LICENSE |
| 354 | +.. _setuptools7560: https://github.com/pypa/setuptools/blob/v75.6.0/pyproject.toml |
| 355 | +.. _spdxlist: https://spdx.org/licenses/ |
| 356 | +.. _spdxtutorial: https://github.com/david-a-wheeler/spdx-tutorial |
0 commit comments