Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
72c7d26
Add missing wheel builds on release CI
AyanSinhaMahapatra Jun 25, 2025
4e5b7fd
Merge pull request #98 from aboutcode-org/update-release-ci
AyanSinhaMahapatra Jun 25, 2025
265e612
Drop python3.9 support and add python 3.14
AyanSinhaMahapatra Oct 21, 2025
fc4fe3a
Support trusted-publishing for package releases
AyanSinhaMahapatra Oct 22, 2025
e81ff6d
Update RTD build python version
AyanSinhaMahapatra Oct 24, 2025
fb75a2e
Merge pull request #99 from aboutcode-org/update-python-support
AyanSinhaMahapatra Oct 24, 2025
cf04877
Deprecate MacOS-13 CI runners
AyanSinhaMahapatra Dec 15, 2025
3c2606a
Merge pull request #100 from aboutcode-org/deprecate-macos-runners
AyanSinhaMahapatra Dec 15, 2025
8682dbf
Typo and spacing corrections.
chinyeungli Feb 23, 2026
ae254b3
Merge pull request #102 from aboutcode-org/enhance_docstring_clarity
chinyeungli Feb 27, 2026
77bd586
Fixed licensing dedup issue #67
chinyeungli Mar 16, 2026
ca2a42a
Added more logically equivalent tests #67
chinyeungli Mar 17, 2026
33840a6
Replace versions with commit hashes in actions
AyanSinhaMahapatra Apr 16, 2026
fa15c37
Merge pull request #103 from aboutcode-org/commit-hash-in-ci
AyanSinhaMahapatra Apr 16, 2026
c3b24ea
Enable zizmor in github actions
AyanSinhaMahapatra Apr 16, 2026
c9cb5a9
Merge pull request #104 from aboutcode-org/enable-zizmor
AyanSinhaMahapatra Apr 16, 2026
819554f
Add tests and simplify comments
AyanSinhaMahapatra May 15, 2026
9f886b9
Update azure pipelines images and python versions
AyanSinhaMahapatra May 15, 2026
abf9ebb
Drop support for python 3.9
AyanSinhaMahapatra May 15, 2026
11ce1e2
Merge remote-tracking branch 'skeleton/main' into 67_dedup_issue
AyanSinhaMahapatra May 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/docs-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: CI Documentation

on: [push, pull_request]

permissions: {}
jobs:
build:
runs-on: ubuntu-24.04
Expand All @@ -13,10 +14,12 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: ${{ matrix.python-version }}

Expand Down
22 changes: 13 additions & 9 deletions .github/workflows/pypi-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
tags:
- "v*.*.*"

permissions: {}
jobs:
build-pypi-distribs:
name: Build and publish library to PyPI
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: 3.13

Expand All @@ -40,7 +43,7 @@
run: python -m twine check dist/*

- name: Upload built archives
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: pypi_archives
path: dist/*
Expand All @@ -57,13 +60,13 @@

steps:
- name: Download built archives
uses: actions/download-artifact@v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131
with:
name: pypi_archives
path: dist

- name: Create GH release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda

Check notice

Code scanning / zizmor

action functionality is already included by the runner Note

action functionality is already included by the runner
Comment thread
AyanSinhaMahapatra marked this conversation as resolved.
Dismissed
with:
draft: true
files: dist/*
Expand All @@ -74,16 +77,17 @@
needs:
- create-gh-release
runs-on: ubuntu-24.04
environment: pypi-publish
permissions:
id-token: write

steps:
- name: Download built archives
uses: actions/download-artifact@v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131
with:
name: pypi_archives
path: dist

- name: Publish to PyPI
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
24 changes: 24 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: GitHub Actions Security Analysis with zizmor 🌈

on:
push:
branches: ["main"]
pull_request:
branches: ["**"]

permissions: {}

jobs:
zizmor:
name: Run zizmor 🌈
runs-on: ubuntu-latest
permissions:
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version: 2

# Build in latest ubuntu/python
build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.11"
python: "3.13"

# Build PDF & ePub
formats:
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ simplify and normalize license expressions (such as SPDX license expressions)
using boolean logic.

- License: Apache-2.0
- Python: 3.9+
- Python: 3.10+
- Homepage: https://github.com/aboutcode-org/license-expression/
- Install: `pip install license-expression` also available in most Linux distro.

Expand Down
30 changes: 15 additions & 15 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,54 @@ jobs:
parameters:
job_name: run_code_checks
image_name: ubuntu-24.04
python_versions: ['3.13']
python_versions: ['3.14']
test_suites:
all: make check

- template: etc/ci/azure-posix.yml
parameters:
job_name: ubuntu22_cpython
image_name: ubuntu-22.04
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv/bin/pytest -n 2 -vvs

- template: etc/ci/azure-posix.yml
parameters:
job_name: ubuntu24_cpython
image_name: ubuntu-24.04
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv/bin/pytest -n 2 -vvs

- template: etc/ci/azure-posix.yml
parameters:
job_name: macos13_cpython
image_name: macOS-13
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
job_name: macos14_cpython
image_name: macos-14
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv/bin/pytest -n 2 -vvs

- template: etc/ci/azure-posix.yml
parameters:
job_name: macos14_cpython
image_name: macOS-14
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
job_name: macos15_cpython
image_name: macos-15
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv/bin/pytest -n 2 -vvs

- template: etc/ci/azure-win.yml
parameters:
job_name: win2025_cpython
image_name: windows-2025
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
job_name: win2022_cpython
image_name: windows-2022
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv\Scripts\pytest -n 2 -vvs

- template: etc/ci/azure-win.yml
parameters:
job_name: win2022_cpython
image_name: windows-2022
python_versions: ["3.9", "3.10", "3.11", "3.12", "3.13"]
job_name: win2025_cpython
image_name: windows-2025
python_versions: ["3.10", "3.11", "3.12", "3.13", "3.14"]
test_suites:
all: venv\Scripts\pytest -n 2 -vvs
6 changes: 3 additions & 3 deletions etc/scripts/utils_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""
Utilities to manage requirements files and call pip.
NOTE: this should use ONLY the standard library and not import anything else
because this is used for boostrapping with no requirements installed.
because this is used for bootstrapping with no requirements installed.
"""


Expand All @@ -31,7 +31,7 @@ def load_requirements(requirements_file="requirements.txt", with_unpinned=False)

def get_required_name_versions(requirement_lines, with_unpinned=False):
"""
Yield required (name, version) tuples given a`requirement_lines` iterable of
Yield required (name, version) tuples given a `requirement_lines` iterable of
requirement text lines. Only accept requirements pinned to an exact version.
"""

Expand All @@ -47,7 +47,7 @@ def get_required_name_versions(requirement_lines, with_unpinned=False):

def get_required_name_version(requirement, with_unpinned=False):
"""
Return a (name, version) tuple given a`requirement` specifier string.
Return a (name, version) tuple given a `requirement` specifier string.
Requirement version must be pinned. If ``with_unpinned`` is True, unpinned
requirements are accepted and only the name portion is returned.

Expand Down
6 changes: 3 additions & 3 deletions etc/scripts/utils_thirdparty.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@
TRACE_ULTRA_DEEP = False

# Supported environments
PYTHON_VERSIONS = "39", "310", "311", "312", "313"
PYTHON_VERSIONS = "310", "311", "312", "313", "314"

PYTHON_DOT_VERSIONS_BY_VER = {
"39": "3.9",
"310": "3.10",
"311": "3.11",
"312": "3.12",
"313": "3.13",
"314": "3.14",
}


Expand All @@ -134,11 +134,11 @@ def get_python_dot_version(version):


ABIS_BY_PYTHON_VERSION = {
"39": ["cp39", "cp39m", "abi3"],
"310": ["cp310", "cp310m", "abi3"],
"311": ["cp311", "cp311m", "abi3"],
"312": ["cp312", "cp312m", "abi3"],
"313": ["cp313", "cp313m", "abi3"],
"314": ["cp314", "cp314m", "abi3"],
}

PLATFORMS_BY_OS = {
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools >= 50", "wheel", "setuptools_scm[toml] >= 6"]
requires = ["setuptools >= 50", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
Expand Down
4 changes: 1 addition & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,14 @@ license_files =
README.rst

[options]
python_requires = >=3.9
python_requires = >=3.10

package_dir =
=src
packages = find:
include_package_data = true
zip_safe = false

setup_requires = setuptools_scm[toml] >= 4

install_requires =
boolean.py >= 4.0

Expand Down
37 changes: 30 additions & 7 deletions src/license_expression/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,12 @@ def dedup(self, expression):

The deduplication:

- Performs the deduplication recusively for all sub-expressions.

- Does not sort the licenses of sub-expression in an expression. They
stay in the same order as in the original expression.
stay in the same order as in the original expression. In case of two
similar expressions joined by AND, sorted differently, the sort order
of the first expression is retained.

- Choices (as in "MIT or GPL") are kept as-is and not treated as
simplifiable. This avoids droping important choice options in complex
Expand Down Expand Up @@ -750,12 +754,31 @@ def dedup(self, expression):
),
):
relation = exp.__class__.__name__
deduped = combine_expressions(
expressions,
relation=relation,
unique=True,
licensing=self,
)
# Flatten nested 'AND' expressions only (not OR) to maintain precedence
Comment thread
AyanSinhaMahapatra marked this conversation as resolved.
if relation == "AND":
flattened = []
for e in expressions:
if isinstance(e, self.AND):
# Flatten nested ANDs by extending with their args
flattened.extend(e.args)
else:
flattened.append(e)
expressions = flattened

unique_expressions = []
for e in expressions:
if e not in unique_expressions:
unique_expressions.append(e)

if len(unique_expressions) == 1:
deduped = unique_expressions[0]
else:
deduped = combine_expressions(
expressions,
relation=relation,
unique=True,
licensing=self,
)
else:
raise ExpressionError(f"Unknown expression type: {expression!r}")
return deduped
Expand Down
Loading