Skip to content

Commit 4fcbb24

Browse files
befelemewebknjaz
andcommitted
Add the licensing examples and user scenarios
Adapted from: - https://peps.python.org/pep-0639/appendix-examples/ - https://peps.python.org/pep-0639/appendix-user-scenarios/ Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
1 parent a8f6ba6 commit 4fcbb24

File tree

2 files changed

+356
-0
lines changed

2 files changed

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