3030from licensedcode .cache import get_licensing
3131from licensedcode .match import LicenseMatch
3232from licensedcode .match import set_matched_lines
33+ from licensedcode .match import is_extra_words_position_valid
3334from licensedcode .models import compute_relevance
3435from licensedcode .models import Rule
3536from licensedcode .models import UnDetectedRule
@@ -110,6 +111,7 @@ class DetectionCategory(Enum):
110111 PACKAGE_ADD_FROM_SIBLING_FILE = 'from-package-sibling-file'
111112 PACKAGE_ADD_FROM_FILE = 'from-package-file'
112113 EXTRA_WORDS = 'extra-words'
114+ EXTRA_WORDS_PERMITTED = 'extra-words-permitted-in-rule'
113115 UNKNOWN_MATCH = 'unknown-match'
114116 LICENSE_CLUES = 'license-clues'
115117 LOW_QUALITY_MATCH_FRAGMENTS = 'low-quality-matches'
@@ -129,6 +131,7 @@ class DetectionRule(Enum):
129131 """
130132 UNKNOWN_MATCH = 'unknown-match'
131133 EXTRA_WORDS = 'extra-words'
134+ EXTRA_WORDS_PERMITTED = 'extra-words-permitted-in-rule'
132135 LICENSE_CLUES = 'license-clues'
133136 LOW_QUALITY_MATCH_FRAGMENTS = 'low-quality-matches'
134137 IMPERFECT_COVERAGE = 'imperfect-match-coverage'
@@ -1072,6 +1075,7 @@ def is_correct_detection_non_unknown(license_matches):
10721075 is_correct_detection (license_matches )
10731076 and not has_unknown_matches (license_matches )
10741077 and not has_extra_words (license_matches )
1078+ and not is_extra_words_at_valid_positions (license_matches )
10751079 )
10761080
10771081
@@ -1159,6 +1163,16 @@ def has_low_rule_relevance(license_matches):
11591163 )
11601164
11611165
1166+ def is_extra_words_at_valid_positions (license_matches ):
1167+ """
1168+ Return True if any of the matches in ``license_matches`` List of LicenseMatch
1169+ has extra words are in the correct place.
1170+ """
1171+ return any (
1172+ is_extra_words_position_valid (license_match )
1173+ for license_match in license_matches
1174+ )
1175+
11621176def is_false_positive (license_matches , package_license = False ):
11631177 """
11641178 Return True if all of the matches in ``license_matches`` List of LicenseMatch
@@ -1570,6 +1584,12 @@ def get_detected_license_expression(
15701584 detection_log .append (DetectionRule .LOW_QUALITY_MATCH_FRAGMENTS .value )
15711585 return detection_log , combined_expression
15721586
1587+ elif analysis == DetectionCategory .EXTRA_WORDS_PERMITTED .value :
1588+ if TRACE_ANALYSIS :
1589+ logger_debug (f'analysis { DetectionCategory .EXTRA_WORDS_PERMITTED .value } ' )
1590+ matches_for_expression = license_matches
1591+ detection_log .append (DetectionRule .EXTRA_WORDS_PERMITTED .value )
1592+
15731593 elif analysis == DetectionCategory .EXTRA_WORDS .value :
15741594 if TRACE_ANALYSIS :
15751595 logger_debug (f'analysis { DetectionCategory .EXTRA_WORDS .value } ' )
@@ -1807,6 +1827,10 @@ def analyze_detection(license_matches, package_license=False):
18071827 threshold = IMPERFECT_MATCH_COVERAGE_THR ,
18081828 ):
18091829 return DetectionCategory .IMPERFECT_COVERAGE .value
1830+
1831+ # Case where `extra-words` are in the right place
1832+ elif is_extra_words_at_valid_positions (license_matches = license_matches ):
1833+ return DetectionCategory .EXTRA_WORDS_PERMITTED .value
18101834
18111835 # Case where at least one of the match have extra words
18121836 elif has_extra_words (license_matches = license_matches ):
0 commit comments