Skip to content

Commit f5baeba

Browse files
committed
1 parent 2f38c66 commit f5baeba

File tree

2 files changed

+359
-0
lines changed

2 files changed

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

source/guides/section-build-and-publish.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ Building and Publishing
1616
making-a-pypi-friendly-readme
1717
publishing-package-distribution-releases-using-github-actions-ci-cd-workflows
1818
modernize-setup-py-project
19+
licensing-examples-and-user-scenarios

0 commit comments

Comments
 (0)