Skip to content

Commit dd5ed07

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 dd5ed07

File tree

2 files changed

+357
-0
lines changed

2 files changed

+357
-0
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
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

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)