@@ -585,47 +585,32 @@ def simple_tokenizer(self, expression):
585585
586586 def dedup (self , expression ):
587587 """
588- Return a de-duplicated expression
588+ Return a de-duplicated LicenseExpression given a license expfession
589+ string or LicenseExpression object.
589590 """
590591 exp = self .parse (expression )
591- dedup_expression = ''
592- expression_list = []
592+ expressions = []
593593 for arg in exp .args :
594- if isinstance (arg , (self .AND , self .OR )):
595- # Run this recursive function if there is another AND/OR expression
596- # and add the expression to the expression_list .
597- expression_list .append (self .dedup (arg ))
594+ if isinstance (arg , (self .AND , self .OR , )):
595+ # Run this recursive function if there is another AND/OR
596+ # expression and add the expression to the expressions list .
597+ expressions .append (self .dedup (arg ))
598598 else :
599- # Get the license key from the expression as a list.
600- exp_key = self .license_keys (arg )
601- # We treat the license with exception as a single license key so
602- # that it won't over de-dupped for case such as
603- # gpl-2.0 WITH classpath exception AND gpl-2.0
604- if type (arg ).__name__ == 'LicenseWithExceptionSymbol' :
605- key = ' WITH ' .join (exp_key )
606- else :
607- # The list should only contains 1 license symbol as the "AND"
608- # and "OR" condition is taken care in the above
609- # isinstance(arg, (self.AND, self.OR)) and the "WITH" condition
610- # is taken care in the above if condition.
611- key = exp_key [0 ]
612- # Add the license key to the expression_list if it's not already
613- # present.
614- if not key in expression_list :
615- expression_list .append (key )
616-
617- if isinstance (expression , self .LicenseSymbol ) or type (expression ).__name__ == 'LicenseWithExceptionSymbol' :
618- dedup_expression = str (expression )
619- elif isinstance (expression , self .AND ):
620- dedup_expression = combine_expressions (expression_list , relation = 'AND' )
621- elif isinstance (expression , self .OR ):
622- dedup_expression = combine_expressions (expression_list , relation = 'OR' )
599+ expressions .append (arg )
600+
601+ if isinstance (exp , BaseSymbol ):
602+ deduped = exp
603+ elif isinstance (exp , (self .AND , self .OR ,)):
604+ relation = exp .__class__ .__name__
605+ deduped = combine_expressions (
606+ expressions ,
607+ relation = relation ,
608+ unique = True ,
609+ licensing = self ,
610+ )
623611 else :
624612 raise Exception ('Unknown expression type: {}' .format (repr (expression )))
625-
626- # Put the parentheses between the expression for grouping purpose.
627- dedup_expression = '({})' .format (dedup_expression )
628- return dedup_expression
613+ return deduped
629614
630615
631616def build_symbols_from_unknown_tokens (tokens ):
@@ -1283,8 +1268,9 @@ def as_symbols(symbols):
12831268 yield LicenseSymbolLike (symbol )
12841269
12851270 else :
1286- raise TypeError ('%(symbol)r is not a unicode string '
1287- 'or a LicenseSymbol-like instance.' % locals ())
1271+ raise TypeError (
1272+ '%(symbol)r is not a unicode string '
1273+ 'or a LicenseSymbol-like instance.' % locals ())
12881274
12891275
12901276def validate_symbols (symbols , validate_keys = False ):
@@ -1399,26 +1385,35 @@ def validate_symbols(symbols, validate_keys=False):
13991385 errors .append ('Invalid key: a key cannot be an expression keyword: %(ikw)s.' % locals ())
14001386
14011387 warnings = []
1402- for dupeal in sorted (dupe_aliases ):
1403- errors .append ('Duplicated or empty aliases ignored for license key: %(dupeal )r.' % locals ())
1388+ for dupe_alias in sorted (dupe_aliases ):
1389+ errors .append ('Duplicated or empty aliases ignored for license key: %(dupe_alias )r.' % locals ())
14041390
14051391 return warnings , errors
14061392
14071393
1408- def combine_expressions (expressions , relation = 'AND' , licensing = Licensing ()):
1394+ def combine_expressions (
1395+ expressions ,
1396+ relation = 'AND' ,
1397+ unique = True ,
1398+ licensing = Licensing (),
1399+ ):
14091400 """
1410- Return a combined license expression string with relation, given a list of
1411- license expressions strings.
1412- For example:
1413- >>> a = 'mit'
1414- >>> b = 'gpl'
1415- >>> combine_expressions([a, b])
1416- 'mit AND gpl'
1417- >>> assert 'mit' == combine_expressions([a])
1418- >>> combine_expressions([])
1419- >>> combine_expressions(None)
1420- >>> combine_expressions(('gpl', 'mit', 'apache',))
1421- 'gpl AND mit AND apache'
1401+ Return a combined LicenseExpression object with the `relation`,
1402+ given a list of license `expressions` strings or LicenseExpression.
1403+ If unique is True remove duplicates before combining expressions.
1404+
1405+ For example::
1406+ >>> a = 'mit'
1407+ >>> b = 'gpl'
1408+ >>> str(combine_expressions([a, b]))
1409+ 'mit AND gpl'
1410+ >>> assert 'mit' == str(combine_expressions([a]))
1411+ >>> combine_expressions([])
1412+ >>> combine_expressions(None)
1413+ >>> str(combine_expressions(('gpl', 'mit', 'apache',)))
1414+ 'gpl AND mit AND apache'
1415+ >>> str(combine_expressions(('gpl', 'mit', 'apache',), relation='OR'))
1416+ 'gpl OR mit OR apache'
14221417 """
14231418 if not expressions :
14241419 return
@@ -1428,14 +1423,15 @@ def combine_expressions(expressions, relation='AND', licensing=Licensing()):
14281423 'expressions should be a list or tuple and not: {}' .format (
14291424 type (expressions )))
14301425
1431- # Remove duplicate element in the expressions list
1432- expressions = list (dict ((x , True ) for x in expressions ).keys ())
1426+ # only del with LicenseExpression objects
1427+ expressions = [licensing .parse (le , simple = True ) for le in expressions ]
1428+
1429+ # Remove duplicate expressions
1430+ if unique :
1431+ expressions = list ({str (x ): x for x in expressions }.values ())
14331432
14341433 if len (expressions ) == 1 :
14351434 return expressions [0 ]
14361435
1437- expressions = [licensing .parse (le , simple = True ) for le in expressions ]
1438- if relation == 'OR' :
1439- return str (licensing .OR (* expressions ))
1440- else :
1441- return str (licensing .AND (* expressions ))
1436+ relation = {'AND' : licensing .AND , 'OR' : licensing .OR }[relation ]
1437+ return relation (* expressions )
0 commit comments