Package: license-expression
license-expressionis a comprehensive utility library to parse, compare,
simplify and normalize license expressions (such as SPDX license expressions)
using boolean logic.License: Apache-2.0Python: 3.7+Homepage:https://github.com/nexB/license-expression/Install:pip install license-expressionalso available in most Linux distro.Software project licenses are often a combination of several free and open
source software licenses. License expressions – as specified by SPDX – provide
a concise and human readable way to express these licenses without having to
read long license texts, while still being machine-readable.License expressions are used by key FOSS projects such as Linux; several
packages ecosystem use them to document package licensing metadata such as
npm and Rubygems; they are important when exchanging software data (such as with
SPDX and SBOM in general) as a way to express licensing precisely.license-expressionis a comprehensive utility library to parse, compare,
simplify and normalize these license expressions (such as SPDX license expressions)
using boolean logic like in:GPL-2.0-or-later WITH Classpath-exception-2.0 AND MIT.It includes the license keys from SPDXhttps://spdx.org/licenses/(version 3.22)
and ScanCode license DB (version 32.0.8, last published on 2023-11-16).
Seehttps://scancode-licensedb.aboutcode.org/to get started quickly.license-expressionis both powerful and simple to use and is a used as the
license expression engine in several projects and products such as:AboutCode-toolkithttps://github.com/nexB/aboutcode-toolkitAlekSIS (School Information System)https://edugit.org/AlekSIS/official/AlekSIS-CoreBaristahttps://github.com/Optum/baristaConda forge toolshttps://github.com/conda-forge/conda-smithyDejaCodehttps://dejacode.comDeltaCodehttps://github.com/nexB/deltacodeFenixscanXhttps://github.com/SmartsYoung/FenixscanXFetchCodehttps://github.com/nexB/fetchcodeFlicthttps://github.com/vinland-technology/flictandhttps://github.com/vinland-technologylicense.shhttps://github.com/webscopeio/license.shliferay_inbound_checkerhttps://github.com/carmenbianca/liferay_inbound_checkerREUSEhttps://reuse.software/andhttps://github.com/fsfe/reuse-toolScanCode-iohttps://github.com/nexB/scancode.ioScanCode-toolkithttps://github.com/nexB/scancode-toolkitSee also for details:
-https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/license-expressionis also packaged for most Linux distributions. See below.Alternative:There is no known alternative library for Python, but there are several similar
libraries in other languages (but not as powerful of course!):JavaScripthttps://github.com/jslicense/spdx-expression-parse.jsRusthttps://github.com/ehuss/license-exprsHaskellhttps://github.com/phadej/spdxGohttps://github.com/kyoh86/go-spdxAdahttps://github.com/Fabien-Chouteau/spdx_adaJavahttps://github.com/spdx/toolsandhttps://github.com/aschet/spdx-license-expression-toolsBuild and tests statusLinux & macOS (Travis)Windows (AppVeyor)Linux, Windows & macOS (Azure)Source code and downloadGitHubhttps://github.com/nexB/license-expression.gitPyPIhttps://pypi.python.org/pypi/license-expressionAlso available in several Linux distros:Arch Linuxhttps://archlinux.org/packages/extra/any/python-license-expression/Debianhttps://packages.debian.org/unstable/source/license-expressionDragonFly BSDhttps://github.com/DragonFlyBSD/DPorts/tree/master/textproc/py-license-expressionFedorahttps://src.fedoraproject.org/rpms/python-license-expression/FreeBSDhttps://www.freshports.org/textproc/py-license-expressionNixOShttps://github.com/NixOS/nixpkgs/blob/release-21.05/pkgs/development/python-modules/license-expression/default.nixopenSUSEhttps://build.opensuse.org/package/show/openSUSE:Factory/python-license-expressionSupportSubmit bugs and questions at:https://github.com/nexB/license-expression/issuesJoin the chat at:https://gitter.im/aboutcode-org/discussDescriptionThis module defines a mini language to parse, validate, simplify, normalize and
compare license expressions using a boolean logic engine.This supports SPDX license expressions and also accepts other license naming
conventions and license identifiers aliases to resolve and normalize any license
expressions.Using boolean logic, license expressions can be tested for equality, containment,
equivalence and can be normalized or simplified.It also bundles the SPDX License list (3.20 as of now) and the ScanCode license
DB (based on latest ScanCode) to easily parse and validate expressions using
the license symbols.Usage examplesThe main entry point is theLicensingobject that you can use to parse,
validate, compare, simplify and normalize license expressions.Create an SPDX Licensing and parse expressions:>>> from license_expression import get_spdx_licensing
>>> licensing = get_spdx_licensing()
>>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
>>> parsed = licensing.parse(expression)
>>> print(parsed.pretty())
OR(
  LicenseSymbol('GPL-2.0-only'),
  AND(
    LicenseSymbol('LGPL-2.1-only'),
    LicenseSymbol('MIT')
  )
)

>>> str(parsed)
'GPL-2.0-only OR (LGPL-2.1-only AND MIT)'

>>> licensing.parse('unknwon with foo', validate=True, strict=True)
license_expression.ExpressionParseError: A plain license symbol cannot be used
as an exception in a "WITH symbol" statement. for token: "foo" at position: 13

>>> licensing.parse('unknwon with foo', validate=True)
license_expression.ExpressionError: Unknown license key(s): unknwon, foo

>>> licensing.validate('foo and MIT and GPL-2.0+')
ExpressionInfo(
    original_expression='foo and MIT and GPL-2.0+',
    normalized_expression=None,
    errors=['Unknown license key(s): foo'],
    invalid_symbols=['foo']
)Create a simple Licensing and parse expressions:>>> from license_expression import Licensing, LicenseSymbol
>>> licensing = Licensing()
>>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
>>> parsed = licensing.parse(expression)
>>> expression = ' GPL-2.0 or LGPL-2.1 and mit '
>>> expected = 'GPL-2.0-only OR (LGPL-2.1-only AND mit)'
>>> assert str(parsed) == expected
>>> assert parsed.render('{symbol.key}') == expectedCreate a Licensing with your own license symbols:>>> expected = [
...   LicenseSymbol('GPL-2.0'),
...   LicenseSymbol('LGPL-2.1'),
...   LicenseSymbol('mit')
... ]
>>> assert licensing.license_symbols(expression) == expected
>>> assert licensing.license_symbols(parsed) == expected

>>> symbols = ['GPL-2.0+', 'Classpath', 'BSD']
>>> licensing = Licensing(symbols)
>>> expression = 'GPL-2.0+ with Classpath or (bsd)'
>>> parsed = licensing.parse(expression)
>>> expected = 'GPL-2.0+ WITH Classpath OR BSD'
>>> assert parsed.render('{symbol.key}') == expected

>>> expected = [
...   LicenseSymbol('GPL-2.0+'),
...   LicenseSymbol('Classpath'),
...   LicenseSymbol('BSD')
... ]
>>> assert licensing.license_symbols(parsed) == expected
>>> assert licensing.license_symbols(expression) == expectedAnd expression can be deduplicated, to remove duplicate license subexpressions
without changing the order and without consider license choices as simplifiable:>>> expression2 = ' GPL-2.0 or (mit and LGPL 2.1) or bsd Or GPL-2.0  or (mit and LGPL 2.1)'
>>> parsed2 = licensing.parse(expression2)
>>> str(parsed2)
'GPL-2.0 OR (mit AND LGPL 2.1) OR BSD OR GPL-2.0 OR (mit AND LGPL 2.1)'
>>> assert str(parsed2.simplify()) == 'BSD OR GPL-2.0 OR (LGPL 2.1 AND mit)'Expression can be simplified, treating them as boolean expressions:>>> expression2 = ' GPL-2.0 or (mit and LGPL 2.1) or bsd Or GPL-2.0  or (mit and LGPL 2.1)'
>>> parsed2 = licensing.parse(expression2)
>>> str(parsed2)
'GPL-2.0 OR (mit AND LGPL 2.1) OR BSD OR GPL-2.0 OR (mit AND LGPL 2.1)'
>>> assert str(parsed2.simplify()) == 'BSD OR GPL-2.0 OR (LGPL 2.1 AND mit)'Two expressions can be compared for equivalence and containment:>>> expr1 = licensing.parse(' GPL-2.0 or (LGPL 2.1 and mit) ')
>>> expr2 = licensing.parse(' (mit and LGPL 2.1)  or GPL-2.0 ')
>>> licensing.is_equivalent(expr1, expr2)
True
>>> licensing.is_equivalent(' GPL-2.0 or (LGPL 2.1 and mit) ',
...                         ' (mit and LGPL 2.1)  or GPL-2.0 ')
True
>>> expr1.simplify() == expr2.simplify()
True
>>> expr3 = licensing.parse(' GPL-2.0 or mit or LGPL 2.1')
>>> licensing.is_equivalent(expr2, expr3)
False
>>> expr4 = licensing.parse('mit and LGPL 2.1')
>>> expr4.simplify() in expr2.simplify()
True
>>> licensing.contains(expr2, expr4)
TrueDevelopmentCheckout a clone fromhttps://github.com/nexB/license-expression.gitThen run./configure--devand thensource tmp/bin/activateon Linux and POSIX.
This will install all dependencies in a local virtualenv, including
development deps.On Windows runconfigure.bat--devand thenScripts\bin\activateinstead.To run the tests, runpytest-vvs