22license-expression
33==================
44
5- license-expression is a comprehensive utility library to parse, compare,
5+ `` license-expression `` is a comprehensive utility library to parse, compare,
66simplify and normalize license expressions (such as SPDX license expressions)
7+ using boolean logic.
8+
9+ - License: Apache-2.0
10+ - Python: 3.6+
11+ - Homepage: https://github.com/nexB/license-expression/
12+ - Install: `pip install license-expression ` also available in most Linux distro.
13+
14+ Software project licenses are often a combination of several free and open
15+ source software licenses. License expressions -- as specified by SPDX -- provide
16+ a concise and human readable way to express these licenses without having to
17+ read long license texts, while still being machine-readable.
18+
19+ License expressions are used by key FOSS projects such as Linux; several
20+ packages ecosystem use them to document package licensing metadata such as
21+ npm and Rubygems; they are important when exchanging software data (such as with
22+ SPDX and SBOM in general) as a way to express licensing precisely.
23+
24+ ``license-expression `` is a comprehensive utility library to parse, compare,
25+ simplify and normalize these license expressions (such as SPDX license expressions)
726using boolean logic like in: `GPL-2.0 or later WITH Classpath Exception AND MIT `.
827
28+ It includes the license keys from SPDX https://spdx.org/licenses/ (version 3.13)
29+ and ScanCode license DB (version 21.6.7) https://scancode-licensedb.aboutcode.org/
30+ to get started quickly.
31+
32+ ``license-expression `` is both powerful and simple to use and is a used as the
33+ license expression engine in several projects and products such as:
34+
35+ - AboutCode-toolkit https://github.com/nexB/aboutcode-toolkit
36+ - AlekSIS (School Information System) https://github.com/AlekSIS-org/AlekSIS-Core
37+ - Barista https://github.com/Optum/barista
38+ - Conda forge tools https://github.com/conda-forge/conda-smithy
39+ - DejaCode https://dejacode.com
40+ - DeltaCode https://github.com/nexB/deltacode
41+ - FenixscanX https://github.com/SmartsYoung/FenixscanX
42+ - FetchCode https://github.com/nexB/fetchcode
43+ - Flict https://github.com/vinland-technology/flict and https://github.com/vinland-technology
44+ - license.sh https://github.com/webscopeio/license.sh
45+ - liferay_inbound_checker https://github.com/carmenbianca/liferay_inbound_checker
46+ - REUSE https://reuse.software/ and https://github.com/fsfe/reuse-tool
47+ - ScanCode-io https://github.com/nexB/scancode.io
48+ - ScanCode-toolkit https://github.com/nexB/scancode-toolkit
49+
950See also for details:
10- https://spdx.org/sites/cpstandard/files/pages/files/spdxversion2.1.pdf#page=95&zoom=auto
51+ - https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/
1152
12- license: apache-2.0
53+ `` license-expression `` is also packaged for most Linux distributions. See below.
1354
14- Python: 3.6+
55+ Alternative:
1556
16- Build and tests status
17- ======================
57+ There is no known alternative library for Python, but there are several similar
58+ libraries in other languages (but not as powerful of course!):
1859
19- .. |travis-master-icon | image :: https://api.travis-ci.org/nexB/license-expression.png?branch=master
20- :target: https://travis-ci.org/nexB/license-expression
21- :alt: MacOSX Master branch tests status
22- :align: middle
60+ - JavaScript https://github.com/jslicense/spdx-expression-parse.js
61+ - Rust https://github.com/ehuss/license-exprs
62+ - Haskell https://github.com/phadej/spdx
63+ - Go https://github.com/kyoh86/go-spdx
64+ - Ada https://github.com/Fabien-Chouteau/spdx_ada
65+ - Java https://github.com/spdx/tools and https://github.com/aschet/spdx-license-expression-tools
2366
24- .. |appveyor-master-icon | image :: https://ci.appveyor.com/api/projects/status/github/nexB/license-expression?svg=true
25- :target: https://ci.appveyor.com/project/nexB/license-expression
26- :alt: Windows Master branch tests status
27- :align: middle
67+ Build and tests status
68+ ======================
2869
29- +-------+ -----------------------+ ----------------------+ ------------------------+
30- | Branch | **Linux (Travis)** |**MacOSX (Travis )** |**Windows (AppVeyor )** |
31- +=======+ =======================+ ======================+ ========================+
32- | | | | |
33- | Master | | travis-master -icon | | |travis-master -icon | | | appveyor-master -icon | |
34- | | | | |
35- +-------+ -----------------------+ ----------------------+ ------------------------+
70+ +--------------------------+ ------------------------+---------- ------------------------+
71+ | **Linux & macOS (Travis)**| **Windows (AppVeyor )** |**Linux, Windows & macOS (Azure )**|
72+ +==========================+ ========================+========== ========================+
73+ | | | |
74+ | | travis-badge -icon | | |appveyor-badge -icon | | | azure-badge -icon | |
75+ | | | |
76+ +--------------------------+ ------------------------+---------- ------------------------+
3677
3778Source code and download
3879========================
3980
40- * https://github.com/nexB/license-expression.git
41- * https://pypi.python.org/pypi/license-expression
42- * https://aur.archlinux.org/packages/python-license-expression/ (Arch Linux through AUR)
81+ - GitHub https://github.com/nexB/license-expression.git
82+ - PyPI https://pypi.python.org/pypi/license-expression
83+
84+ Also available in several Linux distros:
85+
86+ - Arch Linux https://aur.archlinux.org/packages/python-license-expression/
87+ - Debian https://packages.debian.org/unstable/source/license-expression
88+ - DragonFly BSD https://github.com/DragonFlyBSD/DPorts/tree/master/textproc/py-license-expression
89+ - Fedora https://src.fedoraproject.org/rpms/python-license-expression/
90+ - FreeBSD https://www.freshports.org/textproc/py-license-expression
91+ - NixOS https://github.com/NixOS/nixpkgs/blob/release-21.05/pkgs/development/python-modules/license-expression/default.nix
92+ - openSUSE https://build.opensuse.org/package/show/openSUSE:Factory/python-license-expression
93+
4394
4495Support
4596=======
4697
47- Submit bugs and questions at:
48-
49- * https://github.com/nexB/license-expression/issues
98+ - Submit bugs and questions at: https://github.com/nexB/license-expression/issues
99+ - Join the chat at: https://gitter.im/aboutcode-org/discuss
50100
51101Description
52102===========
@@ -55,53 +105,104 @@ This module defines a mini language to parse, validate, simplify, normalize and
55105compare license expressions using a boolean logic engine.
56106
57107This supports SPDX license expressions and also accepts other license naming
58- conventions and license identifiers aliases to resolve and normalize licenses.
108+ conventions and license identifiers aliases to resolve and normalize any license
109+ expressions.
59110
60111Using boolean logic, license expressions can be tested for equality, containment,
61112equivalence and can be normalized or simplified.
62113
63- The main entry point is the Licensing object.
114+ It also bundles the SPDX License list (3.13 as of now) and the ScanCode license
115+ DB (based on ScanCode 21.6.7) to easily parse and validate expressions using
116+ the license symbols.
117+
64118
65119Usage examples
66120==============
67121
68- For example:
122+ The main entry point is the ``Licensing `` object that you can use to parse,
123+ validate, compare, simplify and normalize license expressions.
124+
125+ Create an SPDX Licensing and parse expressions::
126+
127+ >>> from license_expression import get_spdx_licensing
128+ >>> licensing = get_spdx_licensing()
129+ >>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
130+ >>> parsed = licensing.parse(expression)
131+ >>> print(parsed.pretty())
132+ OR(
133+ LicenseSymbol('GPL-2.0-only'),
134+ AND(
135+ LicenseSymbol('LGPL-2.1-only'),
136+ LicenseSymbol('MIT')
137+ )
138+ )
139+
140+ >>> str(parsed)
141+ 'GPL-2.0-only OR (LGPL-2.1-only AND MIT)'
142+
143+ >>> licensing.parse('unknwon with foo', validate=True, strict=True)
144+ license_expression.ExpressionParseError: A plain license symbol cannot be used
145+ as an exception in a "WITH symbol" statement. for token: "foo" at position: 13
146+
147+ >>> licensing.parse('unknwon with foo', validate=True)
148+ license_expression.ExpressionError: Unknown license key(s): unknwon, foo
149+
150+ >>> licensing.validate('foo and MIT and GPL-2.0+')
151+ ExpressionInfo(
152+ original_expression='foo and MIT and GPL-2.0+',
153+ normalized_expression=None,
154+ errors=['Unknown license key(s): foo'],
155+ invalid_symbols=['foo']
156+ )
69157
70- .. code-block :: python
158+
159+ Create a simple Licensing and parse expressions::
71160
72161 >>> from license_expression import Licensing, LicenseSymbol
73162 >>> licensing = Licensing()
74163 >>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
75164 >>> parsed = licensing.parse(expression)
76- >> > expected = ' GPL-2.0 OR (LGPL-2.1 AND mit)'
77- >> > assert expected == parsed.render(' {symbol.key} ' )
165+ >>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
166+ >>> expected = 'GPL-2.0-only OR (LGPL-2.1-only AND mit)'
167+ >>> assert str(parsed) == expected
168+ >>> assert parsed.render('{symbol.key}') == expected
169+
170+
171+ Create a Licensing with your own license symbols::
78172
79173 >>> expected = [
80174 ... LicenseSymbol('GPL-2.0'),
81175 ... LicenseSymbol('LGPL-2.1'),
82176 ... LicenseSymbol('mit')
83177 ... ]
84- >> > assert expected == licensing.license_symbols(expression)
85- >> > assert expected == licensing.license_symbols(parsed)
178+ >>> assert licensing.license_symbols(expression) == expected
179+ >>> assert licensing.license_symbols(parsed) == expected
86180
87181 >>> symbols = ['GPL-2.0+', 'Classpath', 'BSD']
88182 >>> licensing = Licensing(symbols)
89183 >>> expression = 'GPL-2.0+ with Classpath or (bsd)'
90184 >>> parsed = licensing.parse(expression)
91185 >>> expected = 'GPL-2.0+ WITH Classpath OR BSD'
92- >> > assert expected == parsed.render(' {symbol.key} ' )
186+ >>> assert parsed.render('{symbol.key}') == expected
93187
94188 >>> expected = [
95189 ... LicenseSymbol('GPL-2.0+'),
96190 ... LicenseSymbol('Classpath'),
97191 ... LicenseSymbol('BSD')
98192 ... ]
99- >> > assert expected == licensing.license_symbols(parsed)
100- >> > assert expected == licensing.license_symbols(expression)
193+ >>> assert licensing.license_symbols(parsed) == expected
194+ >>> assert licensing.license_symbols(expression) == expected
195+
196+ And expression can be deduplicated, to remove duplicate license subexpressions
197+ without changing the order and without consider license choices as simplifiable::
101198
102- And expression can be simplified:
199+ >>> expression2 = ' GPL-2.0 or (mit and LGPL 2.1) or bsd Or GPL-2.0 or (mit and LGPL 2.1)'
200+ >>> parsed2 = licensing.parse(expression2)
201+ >>> str(parsed2)
202+ 'GPL-2.0 OR (mit AND LGPL 2.1) OR BSD OR GPL-2.0 OR (mit AND LGPL 2.1)'
203+ >>> assert str(parsed2.simplify()) == 'BSD OR GPL-2.0 OR (LGPL 2.1 AND mit)'
103204
104- .. code-block :: python
205+ Expression can be simplified, treating them as boolean expressions::
105206
106207 >>> expression2 = ' GPL-2.0 or (mit and LGPL 2.1) or bsd Or GPL-2.0 or (mit and LGPL 2.1)'
107208 >>> parsed2 = licensing.parse(expression2)
@@ -111,8 +212,6 @@ And expression can be simplified:
111212
112213Two expressions can be compared for equivalence and containment:
113214
114- .. code-block :: python
115-
116215 >>> expr1 = licensing.parse(' GPL-2.0 or (LGPL 2.1 and mit) ' )
117216 >>> expr2 = licensing.parse(' (mit and LGPL 2.1) or GPL-2.0 ' )
118217 >>> licensing.is_equivalent(expr1, expr2)
@@ -134,8 +233,29 @@ Two expressions can be compared for equivalence and containment:
134233Development
135234===========
136235
137- * Checkout a clone from https://github.com/nexB/license-expression.git
138- * Then run ``./configure `` (or ``configure.bat ``) and then ``source bin/activate ``.
139- This will install all vendored dependencies in a local virtualenv, including
236+ - Checkout a clone from https://github.com/nexB/license-expression.git
237+
238+ - Then run ``./configure --dev `` and then ``source tmp/bin/activate ``.
239+ This will install all dependencies in a local virtualenv, including
140240 development deps.
141- * To run the tests, run ``py.test -vvs ``
241+
242+ - On Windows run ``configure.bat --dev `` and then ``Scripts\bin\activate ``.
243+
244+ - To run the tests, run ``pytest -vvs ``
245+
246+
247+ .. |travis-badge-icon | image :: https://api.travis-ci.org/nexB/license-expression.png?branch=master
248+ :target: https://travis-ci.org/nexB/license-expression
249+ :alt: Travis tests status
250+ :align: middle
251+
252+ .. |appveyor-badge-icon | image :: https://ci.appveyor.com/api/projects/status/github/nexB/license-expression?svg=true
253+ :target: https://ci.appveyor.com/project/nexB/license-expression
254+ :alt: Appveyor tests status
255+ :align: middle
256+
257+ .. |azure-badge-icon | image :: https://dev.azure.com/nexB/license-expression/_apis/build/status/nexB.license-expression?branchName=master
258+ :target: https://dev.azure.com/nexB/license-expression/_build/latest?definitionId=2&branchName=master
259+ :alt: Azure pipelines tests status
260+ :align: middle
261+
0 commit comments