def get_declared_license_keys_in_packages(codebase): """ Return a list of declared license keys found in packages. A package manifest (such as Maven POM file or an npm package.json file) contains structured declared license information. This is further normalized as a license_expression. We extract the list of licenses from the normalized license expressions. """ packages = chain.from_iterable( getattr(res, 'packages', []) or [] for res in codebase.walk(topdown=True)) licensing = Licensing() detected_good_licenses = [] for package in packages: expression = package.get('license_expression') if expression: exp = licensing.parse(expression, validate=False, strict=False, simple=True) keys = licensing.license_keys(exp, unique=True) detected_good_licenses.extend(keys) return detected_good_licenses
def _parse_licence_expression(licensing: Licensing, licence_expression: str) -> LicenseExpression: # Removing any unwanted characters so that the expression follows the laws: # > the valid characters are: letters and numbers, underscore, dot, colon or hyphen signs and spaces expression = re.sub(LICENCE_NON_ACCEPTED_CHARACTERS, "", licence_expression) expression = re.sub(r"\([sS]ee [\w\s\.\-]*\)", "", expression) return licensing.parse(expression)
def detect_using_name_mapping(declared): """ Return a license expression detected from a declared_license. """ declared = declared.lower() detected = get_declared_to_detected().get(declared) if detected: licensing = Licensing() return str(licensing.parse(detected, simple=True))
def test_basic(self): setup() print("project: " + str(project)) print("deps: " + str(project.dependencies_pile())) license_set = project.license_set() print("set: " + str(license_set)) dep_pile = project.dependencies_pile() tot_combinations = 1 print("license_set: " + str(license_set)) for proj in dep_pile: proj_license = proj['license'] set_list = license_handler.license_expression_list( proj_license, False).set_list size = len(set_list) tot_combinations = tot_combinations * size print(" * project " + str(proj['name']) + " (" + str(size) + ")") for license_set in set_list: pass #print(" * " + str(license_set)) #for lic in license_set: # print(" * " + str(lic) + ": " ) #print("dependencies: " + str(len(dep_pile))) #print("expanded: " + ','.join(map(str, project.expanded_projects()))) print(str(project.project_combination_list())) #print("license combinations: " + str(self.projects_combinations(license_handler, dep_pile, True))) #print("license combinations: " + str(self.projects_combinations(license_handler, dep_pile, False))) #expanded_project = ProjectExpander(project, license_handler) #print("expanded_project: " + str(expanded_project)) lic = Licensing() EXP = "MIT or MPL-1.1" parsed = lic.parse(EXP) simplified = parsed.simplify() #print("lic: " + parsed) print("lic: " + str(parsed)) print("lic: " + str(lic.parse(EXP).simplify())) print("lic: " + str(parsed.simplify())) print("lic: " + str(simplified))
def get_licence(cls) -> tuple: """Get tuple of licence information of application package.""" # Get string representation of licence in SPDX format licence = getattr(cls, "licence", None) default_dict = { "isDeprecatedLicenseId": False, "isFsfLibre": False, "isOsiApproved": False, "licenseId": "unknown", "name": "Unknown Licence", "referenceNumber": -1, "url": "", } if licence: # Parse licence string into object format licensing = Licensing(LICENSES.keys()) parsed = licensing.parse(licence).simplify() readable = parsed.render_as_readable() # Collect flags about licence combination (drop to False if any licence is False) flags = { "isFsfLibre": True, "isOsiApproved": True, } # Fill information dictionaries with missing data licence_dicts = [] for symbol in parsed.symbols: # Get licence base information, stripping the "or later" mark licence_dict = LICENSES.get(symbol.key.rstrip("+"), None) if licence_dict is None: # Fall back to the default dict licence_dict = default_dict else: # Add missing licence link to SPDX data licence_id = licence_dict["licenseId"] licence_dict["url"] = f"https://spdx.org/licenses/{licence_id}.html" # Drop summed up flags to False if this licence is False flags["isFsfLibre"] = flags["isFsfLibre"] and licence_dict["isFsfLibre"] flags["isOsiApproved"] = flags["isOsiApproved"] and licence_dict["isOsiApproved"] licence_dicts.append(licence_dict) return (readable, flags, licence_dicts) else: # We could not find a valid licence return ("Unknown", [default_dict])
def is_valid_license_expression(expression): """Checks if the given string is a valid SPDX License Expression. >>> print(is_valid_license_expression('MIT or GPL-2.0')) MIT OR GPL-2.0 :param expression: The expression that needs to be verified. :type expression: str :returns: str or None """ licensing = Licensing() try: if(expression == ''): return expression else: parsed = licensing.parse(expression) return parsed.render('{symbol.key}') except: return None
def parse_structured_copyright_file( copyright_file, skip_debian_packaging=True, simplify_licenses=True, unique=True, ): """ Return a tuple of (declared license, detected license_expression, copyrights) strings computed from the `copyright_file` location. For each copyright file paragraph we treat the "name" as a license declaration. The text is used for detection and cross-reference with the declaration. If `skip_debian_packaging` is True, the Debian packaging license --if detected-- is skipped. If `simplify_licenses` is True the license expressions are simplified. If `unique` is True, repeated copyrights, detected or declared licenses are ignore, and only unique detections are returne. """ if not copyright_file: return None, None, None deco = DebianCopyright.from_file(copyright_file) declared_licenses = [] detected_licenses = [] copyrights = [] deco = fix_copyright(deco) licensing = Licensing() for paragraph in deco.paragraphs: if skip_debian_packaging and is_debian_packaging(paragraph): # Skipping packaging license and copyrights since they are not # relevant to the effective package license continue if isinstance(paragraph, (CopyrightHeaderParagraph, CopyrightFilesParagraph)): pcs = paragraph.copyright.statements or [] for p in pcs: p = p.dumps() # avoid repeats if unique: if p not in copyrights: copyrights.append(p) else: copyrights.append(p) if isinstance(paragraph, CatchAllParagraph): text = paragraph.dumps() if text: detected = get_normalized_expression(text, try_as_expression=False) if not detected: detected = 'unknown' detected_licenses.append(detected) else: plicense = paragraph.license if not plicense: continue declared, detected = detect_declared_license(plicense.name) # avoid repeats if unique: if declared and declared not in declared_licenses: declared_licenses.append(declared) if detected and detected not in detected_licenses: detected_licenses.append(detected) else: declared_licenses.append(declared) detected_licenses.append(detected) # also detect in text text = paragraph.license.text if text: detected = get_normalized_expression(text, try_as_expression=False) if not detected: detected = 'unknown' # avoid repeats if unique: if detected not in detected_licenses: detected_licenses.append(detected) else: detected_licenses.append(detected) declared_license = '\n'.join(declared_licenses) if detected_licenses: detected_licenses = [licensing.parse(dl, simple=True) for dl in detected_licenses] if len(detected_licenses) > 1: detected_license = licensing.AND(*detected_licenses) else: detected_license = detected_licenses[0] if simplify_licenses: detected_license = detected_license.simplify() detected_license = str(detected_license) else: detected_license = 'unknown' copyrights = '\n'.join(copyrights) return declared_license, detected_license, copyrights
class LicenseHandler: def __init__(self, translations_files, relicense_file, group_file): self.translations_files = translations_files self.relicense_file = relicense_file self.relicense_map = None self.group_file = group_file symbols = self.read_symbols(self.translations_files) self.licensing = Licensing(symbols) def read_symbols(self, translations_files): symbols_map = {} self.translations = [] for translations_file in translations_files.split(): translation_data = read_translations(translations_file) self.translations.append(translation_data) for lic_key in translation_data: if lic_key not in symbols_map: symbols_map[lic_key] = set() for val in translation_data[lic_key]: symbols_map[lic_key].add(val) return [LicenseSymbol(key=key, aliases=tuple(value)) for key, value in symbols_map.items()] def translate_and_relicense(self, license_expression): transl = self.translate(license_expression) if not transl: transl = license_expression rel = self.expand_relicense(transl) return rel if rel else transl def expand_relicense(self, license_expression): if self.relicense_file is not None and self.relicense_file: self.relicense_map = read_relicense_file(self.relicense_file) expanded = relicense_license( self.relicense_map, license_expression) return expanded.strip() else: return license_expression.strip() def group(self, license_expression): return license_expression.strip() def translate(self, license_expression): license_expression = license_expression.replace( "&", AND_STRING).replace("|", OR_STRING) return str(self.simplify(license_expression)) def simplify(self, license_expression): parsed = self.licensing.parse(license_expression) return parsed.simplify() def license_expression_list_json(self, license_expression, relicense=True): license = self.license_expression_list(license_expression, relicense) return { "license_expression": license_expression, "expanded": license.expanded, "grouped": license.grouped, "translated": license.translated, "simplified": license.simplified, "interim": license.interim, "set_list": license.set_list } def license_expression_list(self, license_expression, relicense=True): license = ManagedLicenseExpression(license_expression) license.translated = self.translate(license_expression) # We need str to skip verbose output license.simplified = str(self.simplify(license.translated)) if relicense: license.expanded = self.expand_relicense(license.simplified) else: license.expanded = license.simplified license.grouped = self.group(license.expanded) license.interim = self.interim_license_expression_list( license.grouped, self.licensing) license.set_list = self.interim_license_expression_set_list( license.interim) return license def interim_license_expression_list(self, license_expression, licensing): """ Transforms and boolean symbolic expression Turns an expression like this: G AND (A OR B) into: AND [G, OR [A, B]] The latter is an interim format. """ encoded = encode_license_expression(license_expression) tokenizer = licensing.get_advanced_tokenizer() tokenized = tokenizer.tokenize(encoded) current_license = None current_licenses = [] current_op = None paren_expr = None paren_count = 0 for token in tokenized: tok = token.string if tok == '(': if paren_expr is None: paren_expr = "" else: paren_expr = paren_expr + " " + tok paren_count = paren_count + 1 elif tok == ')': if paren_count == 0: current_license = self.interim_license_expression_list( paren_expr, licensing) paren_expr = None else: paren_count = paren_count - 1 paren_expr = paren_expr + " " + tok elif tok == 'OR' or tok == 'AND': if paren_expr is not None: paren_expr = paren_expr + " " + tok else: if current_licenses is None: raise FlictError(ReturnCodes.RET_INTERNAL_ERROR, "Internal failure. Failed creating interim license expression. current_licenses is None") if current_op is None: # first operator current_op = tok current_licenses.append(current_license) elif current_op == tok: # same operator current_licenses.append(current_license) else: # different operator raise FlictError(ReturnCodes.RET_INTERNAL_ERROR, "Internal failure. Failed creating interim license expression.") else: if paren_expr is not None: paren_expr = paren_expr + " " + tok else: current_license = tok current_licenses.append(current_license) if current_op is None: current_op = "AND" list = LicenseExpressionList(current_op, current_licenses) return list def _combinations(self, lel): if not isinstance(lel, LicenseExpressionList): return 1 if lel.op == "AND": prod = 1 for item in lel.list: prod = prod * self._combinations(item) return prod elif lel.op == "OR": sum = 0 for item in lel.list: sum = sum + self._combinations(item) return sum else: FlictError(ReturnCodes.RET_INTERNAL_ERROR, f"Internal failure. Failed identifying operator: {lel}") def interim_license_expression_set_list(self, interim_license_expression_list): """ Transforms a boolean symbolic expression Turns an expression like this: AND [G, OR [A, B]] into: [ { G, A }, { G, B } ] The latter is an interim format. """ expanded_list = [] if not isinstance(interim_license_expression_list, LicenseExpressionList): # single license license_set = {decode_license_expression(interim_license_expression_list)} expanded_list.append(list(license_set)) return expanded_list current_op = interim_license_expression_list.op for lep in interim_license_expression_list.list: if current_op is None: raise FlictError(ReturnCodes.RET_INTERNAL_ERROR, "Internal failure. No operator found") lep_list = self.interim_license_expression_set_list(lep) if current_op == "OR": expanded_list = self._manage_list_item_or( expanded_list, lep_list) elif current_op == "AND": expanded_list = self._manage_list_item_and( expanded_list, lep_list) return expanded_list def _manage_list_item_and(self, license_list, lep): if isinstance(lep, LicenseExpressionList): raise FlictError(ReturnCodes.RET_INTERNAL_ERROR, f"Internal failure. Wrong type {lep} for: {lep}") # single license if len(license_list) == 0: return lep new_list = [] for item in license_list: for lep_item in lep: new_item = list(set(item + lep_item)) new_list.append(new_item) return new_list def _manage_list_item_or(self, license_list, lep): if isinstance(lep, LicenseExpressionList): raise FlictError(ReturnCodes.RET_INTERNAL_ERROR, f"Internal failure. Wrong type {lep} for: {lep}") # single license if len(license_list) == 0: return lep new_list = license_list for lep_item in lep: new_list.append(lep_item) return new_list def relicensing_information(self): if self.relicense_map is None: self.relicense_map = read_relicense_file(self.relicense_file) return self.relicense_map def translation_information(self): return self.translations
def get_normalized_expression(query_string): """ Given a text `query_string` return a single detected license expression. `query_string` is typically the value of a license field as found in package manifests. Return None if there is the `query_string` is empty. Return "unknown" as a license expression if there is a `query_string` but nothing was detected. For example:: >>> get_normalized_expression('mit') 'mit' >>> get_normalized_expression('mit or asasa or Apache-2.0') 'apache-2.0 AND unknown' >>> get_normalized_expression('mit or asasa or Apache-2.0') 'apache-2.0 AND unknown' >>> get_normalized_expression('mit asasa or Apache-2.0') 'apache-2.0 AND unknown' >>> assert get_normalized_expression('') is None >>> assert get_normalized_expression(None) is None """ if not query_string or not query_string.strip(): return if TRACE: logger_debug('get_normalized_expression: query_string: "{}"'.format( query_string)) from licensedcode.cache import get_index idx = get_index() licensing = Licensing() # we match twice in a cascade: as an expression, then as plain text if we # did not succeed. matches = None try: matched_as_expression = True matches = idx.match(query_string=query_string, as_expression=True) if matches_have_unknown(matches, licensing): # rematch also if we have unknowns matched_as_expression = False matches = idx.match(query_string=query_string, as_expression=False) except Exception: matched_as_expression = False matches = idx.match(query_string=query_string, as_expression=False) if not matches: # we have a query_string text but there was no match: return an unknown # key return 'unknown' if TRACE: logger_debug('get_normalized_expression: matches:', matches) # join the possible multiple detected license expression with an AND expression_objects = [m.rule.license_expression_object for m in matches] if len(expression_objects) == 1: combined_expression_object = expression_objects[0] else: combined_expression_object = licensing.AND(*expression_objects) if matched_as_expression: # then just return the expression(s) return str(combined_expression_object) # Otherwise, verify that we consumed 100% of the query string e.g. that we # have no unknown leftover. # 1. have all matches 100% coverage? all_matches_have_full_coverage = all(m.coverage() == 100 for m in matches) # TODO: have all matches a high enough score? # 2. are all declared license tokens consumed? query = matches[0].query # the query object should be the same for all matches. Is this always true?? for mt in matches: if mt.query != query: # FIXME: the expception may be swallowed in callers!!! raise Exception( 'Inconsistent package.declared_license: text with multiple "queries".' 'Please report this issue to the scancode-toolkit team.\n' '{}'.format(query_string)) query_len = len(query.tokens) matched_qspans = [m.qspan for m in matches] matched_qpositions = Span.union(*matched_qspans) len_all_matches = len(matched_qpositions) declared_license_is_fully_matched = query_len == len_all_matches if not all_matches_have_full_coverage or not declared_license_is_fully_matched: # We inject an 'unknown' symbol in the expression unknown = licensing.parse('unknown', simple=True) combined_expression_object = licensing.AND(combined_expression_object, unknown) return str(combined_expression_object)
def cli(licenses_file): """ Create rules from a structured text file For instance: ---------------------------------------- license_expression: lgpl-2.1 relevance: 100 is_license_notice: yes --- This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation; ---------------------------------------- """ rule_data = load_data(licenses_file) rules_tokens = set() licenses = cache.get_licenses_db() licensing = Licensing(licenses.values()) print() for data, text in rule_data: rdat = '\n'.join(data) rtxt = '\n'.join(text) existing = rule_exists(rtxt) if existing: print('Skipping existing rule:', existing, 'with text:\n', rtxt[:50].strip(), '...') continue # validate YAML syntax parsed = saneyaml.load(rdat) if parsed.get('is_negative'): license_expression = 'not-a-license' else: _, _, license_expression = data[0].partition(': ') license_expression = license_expression.strip() if not license_expression: raise Exception('Missing license_expression for text:', rtxt) licensing.parse(license_expression, validate=True, simple=True) base_loc = find_rule_base_loc(license_expression) data_file = base_loc + '.yml' with io.open(data_file, 'w', encoding='utf-8') as o: o.write(rdat) text_file = base_loc + '.RULE' with io.open(text_file, 'w', encoding='utf-8') as o: o.write(rtxt) rule = models.Rule(data_file=data_file, text_file=text_file) rule_tokens = tuple(rule.tokens()) if rule_tokens in rules_tokens: # cleanup os.remove(text_file) os.remove(data_file) print('Skipping already added rule with text for:', license_expression) else: rules_tokens.add(rule_tokens) rule.dump() models.update_ignorables(rule, verbose=True) print('Rule added:', rule.identifier)
def cli(licenses_file): """ Create rules from a text file with delimited blocks of metadata and texts. As an example a file would contains one of more blocks such as this: \b ---------------------------------------- license_expression: lgpl-2.1 relevance: 100 is_license_notice: yes --- This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation; ---------------------------------------- """ rules_data = load_data(licenses_file) rules_tokens = all_rule_tokens() licenses = cache.get_licenses_db() licensing = Licensing(licenses.values()) print() errors = validate_license_rules(rules_data, licensing) if errors: print('Invalid rules: exiting....') for error in errors: print(error) print() raise Exception('Invalid rules: exiting....') print() for rule in rules_data: is_negative = rule.data.get('is_negative') is_false_positive = rule.data.get('is_false_positive') existing = rule_exists(rule.text) if existing and not is_negative: print('Skipping existing non-negative rule:', existing, 'with text:\n', rule.text[:50].strip(), '...') continue if is_negative: base_name = 'not-a-license' else: license_expression = rule.data.get('license_expression') license_expression = str( licensing.parse(license_expression, validate=True, simple=True)) base_name = license_expression if is_false_positive: base_name = 'false-positive_' + base_name base_loc = find_rule_base_loc(base_name) data_file = base_loc + '.yml' with io.open(data_file, 'w', encoding='utf-8') as o: o.write(rule.raw_data) text_file = base_loc + '.RULE' with io.open(text_file, 'w', encoding='utf-8') as o: o.write(rule.text) rulerec = models.Rule(data_file=data_file, text_file=text_file) rule_tokens = tuple(rulerec.tokens()) if rule_tokens in rules_tokens: # cleanup os.remove(text_file) os.remove(data_file) print('Skipping already added rule with text for:', base_name) else: rules_tokens.add(rule_tokens) rulerec.dump() models.update_ignorables(rulerec, verbose=False) print( 'Rule added:', 'file://' + rulerec.data_file, '\n', 'file://' + rulerec.text_file, )
class LicenseHandler: def __init__(self, translations_files, relicense_file, group_file): self.translations_files = translations_files self.relicense_file = relicense_file self.relicense_map = None self.group_file = group_file symbols = self.read_symbols(self.translations_files) self.licensing = Licensing(symbols) #print("symbols: " + str(symbols)) def read_symbols(self, translations_files): symbols = [] symbols_map = {} for translations_file in translations_files.split(): #print("reading translation file: " + str(translations_file)) translation_data = read_translations(translations_file) for lic_key in translation_data: #print("lic_key: \"" + str(lic_key) + "\"") #print(" lic_alias: " + str(translation_data[lic_key] )) if lic_key not in symbols_map: symbols_map[lic_key] = set() for val in translation_data[lic_key]: symbols_map[lic_key].add(val) #lic_aliases = tuple(translation_data[lic_key]) #symbols.append(LicenseSymbol(key=key, aliases=lic_aliases)) for key, value in symbols_map.items(): #print("Adding to symbols: " + key) #print(" - " + str(value)) symbols.append(LicenseSymbol(key=key, aliases=tuple(value))) # debugging #print("Symbols") #for sym in symbols: #print(" sym: " + (str(sym.key))) #print(" aliases : " + (str(sym.aliases))) #l = Licensing([sym]) #print(" licensing: " + (str(l))) #print("symbols: " + str(symbols)) return symbols def translate_and_relicense(self, license_expression): license_expression = license_expression.replace("&", " and ").replace("|", " or ") transl = self.translate(license_expression) if transl == None or transl == "": transl = license_expression #print("translate_and_relicenseself: " + license_expression + " ==> " + transl) rel = self.expand_relicense(transl) if rel == None: rel = transl #print("translate_and_relicenseself: " + rel) return rel def expand_relicense(self, license_expression): if self.relicense_file != None and self.relicense_file != "": self.relicense_map = read_relicense_file(self.relicense_file) expanded = relicense_license(self.relicense_map, license_expression) return expanded.strip() else: return license_expression.strip() def group(self, license_expression): return license_expression.strip() def translate(self, license_expression): return str(self.simplify(license_expression)) def simplify(self, license_expression): parsed = self.licensing.parse(license_expression) #parsed = self.licensing._parse_and_simplify(license_expression) #print("simplified: " + str(parsed.simplify())) #return parsed.simplify() return parsed def license_expression_list_json(self, license_expression, relicense=True): license = self.license_expression_list(license_expression, relicense) output = {} output["license_expression"] = license_expression output["expanded"] = license.expanded output["grouped"] = license.grouped output["translated"] = license.translated output["simplified"] = license.simplified output["interim"] = license.interim output["set_list"] = license.set_list return output def license_expression_list(self, license_expression, relicense=True): license = ManagedLicenseExpression(license_expression) license.translated = self.translate(license_expression) if relicense: license.expanded = self.expand_relicense(license.translated) else: license.expanded = license.translated license.grouped = self.group(license.expanded) # We need str to skip verbose output license.simplified = str(self.simplify(license.grouped)) license.interim = self.interim_license_expression_list(license.simplified, self.licensing) license.set_list = self.interim_license_expression_set_list(license.interim) return license def interim_license_expression_list(self, license_expression, licensing): """ Turns an expression like this: G AND (A OR B) into: AND [G, OR [A, B]] The latter is an interim format. """ #print("") #print("parse(" + str(license_expression) + ")") tokenizer = licensing.get_advanced_tokenizer() tokenized = tokenizer.tokenize(str(license_expression)) current_license=None current_licenses=[] current_op=None paren_expr = None paren_count=0 for token in tokenized: tok = token.string if tok == '(': #print("(") if paren_expr == None: paren_expr = "" else: paren_expr = paren_expr + " " + tok paren_count = paren_count + 1 elif tok == ')': #print("about to parse: \"" + paren_expr + "\" count: " + str(paren_count)) if paren_count == 0: current_license = self.interim_license_expression_list(paren_expr, licensing) #print("got: \"" + str(current_license) + "\"") paren_expr=None else: paren_count = paren_count - 1 paren_expr = paren_expr + " " + tok elif tok == 'OR' or tok == 'AND': if paren_expr != None: #print("TEMP " + tok) paren_expr = paren_expr + " " + tok else: #print("OPERATOR " + tok + " (" + str(current_op) + ")") if current_licenses == None: print("ERROR......") print("ERROR......") print("ERROR......") exit(24) if current_op == None: # first operator current_op = tok #print("=cop: " + tok + " " + current_license) current_licenses.append(current_license) elif current_op == tok: # same operator #print("-cop: " + tok + " " + current_license) current_licenses.append(current_license) else: # different operator print("-------------------------------------------- Store me: " + current_op + " " + str(current_licenses)) exit(12) else: #print("tok: \"" + tok + "\"") if paren_expr != None: #print("TEMP " + tok) paren_expr = paren_expr + " " + tok else: #print("license: " + tok) current_license = tok current_licenses.append(current_license) if current_op == None: current_op = "AND" list = LicenseExpressionList(current_op, current_licenses) #print("DONE: " + str(license_expression) + " => " + str(list)) return list def _combinations(self, lel): #print("lel : " + str(lel)) if not isinstance(lel, LicenseExpressionList): return 1 if lel.op == "AND": prod = 1 for l in lel.list: prod = prod * _combinations(l) return prod elif lel.op == "OR": sum = 0 for l in lel.list: sum = sum + _combinations(l) return sum else: print("ERROR: NO OP") exit(11) def interim_license_expression_set_list(self, interim_license_expression_list): """ Turns an expression like this: AND [G, OR [A, B]] into: [ { G, A }, { G, B } ] The latter is an interim format. """ expanded_list=[] #print("Count: " + str(_combinations(interim_license_expression_list))) if not isinstance(interim_license_expression_list, LicenseExpressionList): # single license license_set= { interim_license_expression_list } expanded_list.append(list(license_set)) license_verbose_debug("LEAF, returning " + str(expanded_list)) license_verbose_debug("cop: " + interim_license_expression_list ) #print("managed____ \"" + str(expanded_list) + "\" <---- MIDDLE") return expanded_list current_op = interim_license_expression_list.op; license_verbose_debug("cop: " + current_op ) for lep in interim_license_expression_list.list: license_verbose_debug(" ------ lep ----- " + str(lep)) if current_op == None: print("ERROR: NO OP") exit(11) elif current_op == "OR": lep_list = self.interim_license_expression_set_list(lep) expanded_list = self._manage_list_item_or(expanded_list, lep_list) elif current_op == "AND": lep_list = self.interim_license_expression_set_list(lep) expanded_list = self._manage_list_item_and(expanded_list, lep_list) #print("managed____ \"" + str(expanded_list) + "\" <---- FINAL") return expanded_list def _manage_list_item_and(self, license_list, lep): license_verbose_debug(" * Andy" ) if isinstance(lep, LicenseExpressionList): print(" -------------====== Andy ====-----------------" ) exit(77) # TODO : implement below (for lep) print("AND Count 0: " + str(_combinations(lep))) for inner_lep in lep.list: print("¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ AND Count A: " + str(_combinations(inner_lep))) set_list = self.interim_license_expression_set_list(inner_lep) return None else: # single license if len(license_list) == 0: license_verbose_debug("wooops: " + str(license_list)) license_verbose_debug("wooops: " + str(lep)) license_list = lep else: license_verbose_debug("daisy: " + str(license_list)) license_verbose_debug("daisy: " + str(lep)) license_verbose_debug(" -------------====== Andy ====----------------- SINGLE: " + str(license_list) ) new_list=[] for item in license_list: license_verbose_debug(" item: " + str(item) + " <--- " + str(lep) ) for lep_item in lep: license_verbose_debug(" item: " + str(item) + " <--- " + str(lep_item) ) new_item =list(set(item + lep_item)) license_verbose_debug(" item: " + str(item) ) new_list.append(new_item) license_verbose_debug(" list: " + str(new_list) ) license_list = new_list return license_list def _manage_list_item_or(self, license_list, lep): license_verbose_debug(" * Orleans: " + (str(lep))) if isinstance(lep, LicenseExpressionList): # TODO : implement below (for lep) license_verbose_debug(" -------------====== ORLEANS ====----------------- : " + str(lep.license_list) ) exit(77) for inner_lep in lep.license_list: print(" ====----------------- : " + str(inner_lep) ) print("OR Count A: " + str(_combinations(inner_lep))) set_list = self.interim_license_expression_set_list(inner_lep) print("OR Count B: " + str(len(set_list))) license_list.append(inner_lep) else: # single license license_verbose_debug("HERE I AM .... \"" + str(lep) + "\"") if len(license_list) == 0: new_list=lep license_verbose_debug("topsss: " + str(license_list) + " size: " + str(len(license_list))) license_verbose_debug("topsss: " + str(lep) + " size: " + str(len(lep))) license_verbose_debug("topsss: " + str(new_list) + " size: " + str(len(new_list))) else: new_list = license_list license_verbose_debug("dapsss: " + str(license_list)) license_verbose_debug("dappss: " + str(lep)) for lep_item in lep: license_verbose_debug(" item: " + str(license_list) + " <--- " + str(lep_item) ) new_list.append(lep_item) return new_list