Skip to content

Commit 77bd586

Browse files
committed
Fixed licensing dedup issue #67
Signed-off-by: Chin Yeung Li <tli@nexb.com>
1 parent a3c00c0 commit 77bd586

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

src/license_expression/__init__.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -750,12 +750,33 @@ def dedup(self, expression):
750750
),
751751
):
752752
relation = exp.__class__.__name__
753-
deduped = combine_expressions(
754-
expressions,
755-
relation=relation,
756-
unique=True,
757-
licensing=self,
758-
)
753+
# Flatten nested 'AND' expressions only (not OR) to maintain precedence
754+
# Example: (A AND B) AND (C OR D) will become A AND B AND (C OR D)
755+
# The OR will not be flattened to avoid changing the expression logic
756+
if relation == "AND":
757+
flattened = []
758+
for e in expressions:
759+
if isinstance(e, self.AND):
760+
# Flatten nested ANDs by extending with their args
761+
flattened.extend(e.args)
762+
else:
763+
flattened.append(e)
764+
expressions = flattened
765+
766+
unique_expressions = []
767+
for e in expressions:
768+
if e not in unique_expressions:
769+
unique_expressions.append(e)
770+
771+
if len(unique_expressions) == 1:
772+
deduped = unique_expressions[0]
773+
else:
774+
deduped = combine_expressions(
775+
expressions,
776+
relation=relation,
777+
unique=True,
778+
licensing=self,
779+
)
759780
else:
760781
raise ExpressionError(f"Unknown expression type: {expression!r}")
761782
return deduped

tests/test_license_expression.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,20 @@ def test_dedup_expressions_can_be_simplified_2(self):
693693
expected = l.parse("(mit AND (mit OR bsd-new)) OR mit")
694694
assert result == expected
695695

696+
def test_dedup_expressions_can_be_simplified_3(self):
697+
l = Licensing()
698+
exp = "(gpl AND mit) AND mit AND (gpl OR mit)"
699+
result = l.dedup(exp)
700+
expected = l.parse("gpl AND mit AND (gpl OR mit)")
701+
assert result == expected
702+
703+
def test_dedup_expressions_can_be_simplified_4(self):
704+
l = Licensing()
705+
exp = "(gpl AND mit) AND (mit AND gpl) AND (gpl OR mit)"
706+
result = l.dedup(exp)
707+
expected = l.parse("gpl AND mit AND (gpl OR mit)")
708+
assert result == expected
709+
696710
def test_dedup_expressions_multiple_occurrences(self):
697711
l = Licensing()
698712
exp = " GPL-2.0 or (mit and LGPL-2.1) or bsd Or GPL-2.0 or (mit and LGPL-2.1)"

0 commit comments

Comments
 (0)