def generate_capabilities_map(bears_by_lang): """ Generates a dictionary of capabilities, languages and the corresponding bears from the given ``bears_by_lang`` dict. :param bears_by_lang: dict with language names as keys and the list of bears as values. :returns: dict of the form { "language": { "detect": [list, of, bears] "fix": [list, of, bears] } } """ def nested_dict(): return defaultdict(dict) capabilities_meta = defaultdict(nested_dict) # collectiong the capabilities meta-data for lang, bears in bears_by_lang.items(): can_detect_meta = inverse_dicts(*[{ bear: list(bear.CAN_DETECT) } for bear in bears]) can_fix_meta = inverse_dicts(*[{ bear: list(bear.CAN_FIX) } for bear in bears]) for capability, bears in can_detect_meta.items(): capabilities_meta[capability][lang]['DETECT'] = bears for capability, bears in can_fix_meta.items(): capabilities_meta[capability][lang]['FIX'] = bears return capabilities_meta
def generate_capabilties_map(bears_by_lang): """ Generates a dictionary of capabilities, languages and the corresponding bears from the given ``bears_by_lang`` dict. :param bears_by_lang: dict with language names as keys and the list of bears as values. :returns: dict of the form { "language": { "detect": [list, of, bears] "fix": [list, of, bears] } } """ def nested_dict(): return defaultdict(dict) capabilities_meta = defaultdict(nested_dict) # collectiong the capabilities meta-data for lang, bears in bears_by_lang.items(): can_detect_meta = inverse_dicts( *[{bear: list(bear.CAN_DETECT)} for bear in bears]) can_fix_meta = inverse_dicts( *[{bear: list(bear.CAN_FIX)} for bear in bears]) for capability, bears in can_detect_meta.items(): capabilities_meta[capability][lang]['DETECT'] = bears for capability, bears in can_fix_meta.items(): capabilities_meta[capability][lang]['FIX'] = bears return capabilities_meta
def mode_json(args, debug=False): import json from coalib.coala_main import run_coala from coalib.misc.DictUtilities import inverse_dicts from coalib.misc.Exceptions import get_exitcode from coalib.output.Logging import configure_json_logging from coalib.output.JSONEncoder import create_json_encoder if args.log_json: log_stream = configure_json_logging() JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: from coalib.parsing.FilterHelper import FilterHelper local_bears, global_bears = FilterHelper.apply_filter( 'language', args.filter_by_language) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception) else: results, exitcode, _ = run_coala(args=args, debug=debug) retval = {'bears': results} if args.show_bears else {'results': results} if args.log_json: retval['logs'] = [ json.loads(line) for line in log_stream.getvalue().splitlines() ] if args.output: filename = str(args.output[0]) with open(filename, 'w+') as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': ')) else: print( json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': '))) return 0 if args.show_bears else exitcode
def test_inverse_dicts(self): self.dict1 = {1: [1, 2, 3], 2: [3, 4, 5]} self.dict2 = {2: [1], 3: [2], 4: [3, 4]} self.dict3 = {1: 2, 3: 4, 4: 4, 5: 4} self.dict4 = {2: 3, 4: 4} result = inverse_dicts(self.dict3) self.assertEqual({2: [1], 4: [3, 4, 5]}, result) result = inverse_dicts(self.dict1) self.assertEqual({1: [1], 2: [1], 3: [1, 2], 4: [2], 5: [2]}, result) result = inverse_dicts(self.dict3, self.dict4) self.assertEqual({2: [1], 3: [2], 4: [3, 4, 5, 4]}, result) result = inverse_dicts(self.dict1, self.dict2) self.assertEqual({1: [1, 2], 2: [1, 3], 3: [1, 2, 4], 4: [2, 4], 5: [2]}, result)
def get_bears(): """ Get a dict of bears with the bear class as key. :return: A dict with bear classes as key and the list of sections as value. """ log_printer = LogPrinter(NullPrinter()) sections, _ = load_configuration(None, log_printer) local_bears, global_bears = collect_all_bears_from_sections( sections, log_printer) return inverse_dicts(local_bears, global_bears)
def main(): # Note: We parse the args here once to find the log printer to use. # Also, commands like -h (help) and -v (version) are executed here. # The args are again parsed later to find the settings and configs # to use during analysis. arg_parser = default_arg_parser() args = arg_parser.parse_args() log_printer = None if args.text_logs else ListLogPrinter() JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: local_bears, global_bears = get_filtered_bears( args.filter_by_language, log_printer) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception, log_printer) else: results, exitcode, _ = run_coala(log_printer=log_printer, autoapply=False) retval = {"bears": results} if args.show_bears else {"results": results} if not args.text_logs: retval["logs"] = log_printer.logs if args.output: filename = str(args.output[0]) with open(filename, 'w+') as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': ')) else: print( json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': '))) return 0 if args.show_bears else exitcode
def main(): # Note: We parse the args here once to find the log printer to use. # Also, commands like -h (help) and -v (version) are executed here. # The args are again parsed later to find the settings and configs # to use during analysis. arg_parser = default_arg_parser() args = arg_parser.parse_args() log_printer = None if args.text_logs else ListLogPrinter() JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: local_bears, global_bears = get_filtered_bears( args.filter_by_language, log_printer) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception, log_printer) else: results, exitcode, _ = run_coala( log_printer=log_printer, autoapply=False) retval = {"bears": results} if args.show_bears else {"results": results} if not args.text_logs: retval["logs"] = log_printer.logs if args.output: filename = str(args.output[0]) with open(filename, 'w+') as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': ')) else: print(json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': '))) return 0 if args.show_bears else exitcode
def show_bears(local_bears, global_bears, console_printer): """ Extracts all the bears from each enabled section or the sections in the targets and passes a dictionary to the show_bears_callback method. :param local_bears: Dictionary of local bears with section names as keys and bear list as values. :param global_bears: Dictionary of global bears with section names as keys and bear list as values. :param show_bears_callback: The callback that is used to print these bears. It will get one parameter holding bears as key and the list of section names where it's used as values. """ bears = inverse_dicts(local_bears, global_bears) print_bears(console_printer, bears)
def mode_json(args): import json from coalib.coala_main import run_coala from coalib.misc.DictUtilities import inverse_dicts from coalib.misc.Exceptions import get_exitcode from coalib.output.JSONEncoder import create_json_encoder from coalib.output.printers.LogPrinter import LogPrinter from coalib.parsing.DefaultArgParser import default_arg_parser from coalib.settings.ConfigurationGathering import get_filtered_bears JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: local_bears, global_bears = get_filtered_bears( args.filter_by_language, LogPrinter()) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception) else: results, exitcode, _ = run_coala() retval = {'bears': results} if args.show_bears else {'results': results} if args.output: filename = str(args.output[0]) with open(filename, 'w+') as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': ')) else: print(json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': '))) return 0 if args.show_bears else exitcode
def mode_json(args): import json from coalib.coala_main import run_coala from coalib.misc.DictUtilities import inverse_dicts from coalib.misc.Exceptions import get_exitcode from coalib.output.JSONEncoder import create_json_encoder from coalib.output.printers.LogPrinter import LogPrinter from coalib.settings.ConfigurationGathering import get_filtered_bears JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: local_bears, global_bears = get_filtered_bears( args.filter_by_language, LogPrinter()) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception) else: results, exitcode, _ = run_coala() retval = {'bears': results} if args.show_bears else {'results': results} if args.output: filename = str(args.output[0]) with open(filename, 'w+') as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': ')) else: print( json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(',', ': '))) return 0 if args.show_bears else exitcode
def show_bears(local_bears, global_bears, show_description, show_params, console_printer): """ Extracts all the bears from each enabled section or the sections in the targets and passes a dictionary to the show_bears_callback method. :param local_bears: Dictionary of local bears with section names as keys and bear list as values. :param global_bears: Dictionary of global bears with section names as keys and bear list as values. :param show_description: True if the main description of the bears should be shown. :param show_params: True if the parameters and their description should be shown. :param console_printer: Object to print messages on the console. """ bears = inverse_dicts(local_bears, global_bears) print_bears(bears, show_description, show_params, console_printer)
def show_bears(local_bears, global_bears, compress, console_printer): """ Extracts all the bears from each enabled section or the sections in the targets and passes a dictionary to the show_bears_callback method. :param local_bears: Dictionary of local bears with section names as keys and bear list as values. :param global_bears: Dictionary of global bears with section names as keys and bear list as values. :param compress: If set to true, output will be compressed (just show bear names as a list) :param show_bears_callback: The callback that is used to print these bears. It will get one parameter holding bears as key and the list of section names where it's used as values. """ bears = inverse_dicts(local_bears, global_bears) print_bears(console_printer, bears, compress)
def mode_json(args): import json from coalib.coala_main import run_coala from coalib.misc.DictUtilities import inverse_dicts from coalib.misc.Exceptions import get_exitcode from coalib.output.Logging import configure_json_logging from coalib.output.JSONEncoder import create_json_encoder from coalib.output.printers.LogPrinter import LogPrinter from coalib.settings.ConfigurationGathering import get_filtered_bears if args.log_json: log_stream = configure_json_logging() JSONEncoder = create_json_encoder(use_relpath=args.relpath) results = [] if args.show_bears: try: local_bears, global_bears = get_filtered_bears(args.filter_by_language, LogPrinter()) bears = inverse_dicts(local_bears, global_bears) for bear, _ in sorted(bears.items(), key=lambda bear_tuple: bear_tuple[0].name): results.append(bear) except BaseException as exception: # pylint: disable=broad-except return get_exitcode(exception) else: results, exitcode, _ = run_coala() retval = {"bears": results} if args.show_bears else {"results": results} if args.log_json: retval["logs"] = [json.loads(line) for line in log_stream.getvalue().splitlines()] if args.output: filename = str(args.output[0]) with open(filename, "w+") as fp: json.dump(retval, fp, cls=JSONEncoder, sort_keys=True, indent=2, separators=(",", ": ")) else: print(json.dumps(retval, cls=JSONEncoder, sort_keys=True, indent=2, separators=(",", ": "))) return 0 if args.show_bears else exitcode
def show_bears(local_bears, global_bears, show_description, show_params, console_printer, args=None): """ Extracts all the bears from each enabled section or the sections in the targets and passes a dictionary to the show_bears_callback method. :param local_bears: Dictionary of local bears with section names as keys and bear list as values. :param global_bears: Dictionary of global bears with section names as keys and bear list as values. :param show_description: This parameter is deprecated. :param show_params: This parameter is deprecated. :param console_printer: Object to print messages on the console. :param args: Args passed to coala command. """ bears = inverse_dicts(local_bears, global_bears) print_bears(bears, show_description, show_params, console_printer, args)
def filter_relevant_bears(used_languages, arg_parser=None): """ From the bear dict, filter the bears per relevant language. :param used_languages: A list of tuples with language name as the first element and percentage usage as the second element; sorted by percentage usage. :return: A dict with language name as key and bear classes as value. """ log_printer = LogPrinter(NullPrinter()) used_languages.append(("All", 100)) all_bears_by_lang = { lang: set( inverse_dicts( *get_filtered_bears([lang], log_printer, arg_parser)).keys()) for lang, _ in used_languages } bears_by_lang = {} for lang in all_bears_by_lang: if lang in IMPORTANT_BEAR_LIST: bears_by_lang[lang] = { bear for bear in all_bears_by_lang[lang] if bear.name in IMPORTANT_BEAR_LIST[lang] } else: bears_by_lang[lang] = all_bears_by_lang[lang] # Each language would also have the language independent bears. We remove # those and put them in the "All" category. lang_bears = { lang: bears_by_lang[lang] - bears_by_lang["All"] for lang, _ in used_languages } lang_bears["All"] = bears_by_lang["All"] return lang_bears
def filter_relevant_bears(used_languages): """ From the bear dict, filter the bears per relevant language. :param used_languages: A list of tuples with language name as the first element and percentage usage as the second element; sorted by percentage usage. :return: A dict with language name as key and bear classes as value. """ log_printer = LogPrinter(NullPrinter()) used_languages.append(("All", 100)) bears_by_lang = {lang: set(inverse_dicts(*get_filtered_bears( [lang], log_printer)).keys()) for lang, _ in used_languages} # Each language would also have the language independent bears. We remove # those and put them in the "All" category. lang_bears = {lang: bears_by_lang[lang] - bears_by_lang["All"] for lang, _ in used_languages} lang_bears["All"] = bears_by_lang["All"] return lang_bears
def filter_relevant_bears(used_languages, printer, arg_parser, extracted_info, log_printer=None): """ From the bear dict, filter the bears per relevant language. :param used_languages: A list of tuples with language name as the first element and percentage usage as the second element; sorted by percentage usage. :param printer: ``ConsolePrinter`` object to be used for console interactions. :param arg_parser: ``argparse.ArgumentParser`` object containing the arguments passed. :param extracted_info: list of information extracted from ``InfoExtractor`` classes. :return: A dict with language name as key and bear classes as value. """ args = arg_parser.parse_args() if arg_parser else None used_languages.append(('All', 100)) bears_by_lang = { lang: set(inverse_dicts(*get_filtered_bears([lang], log_printer, arg_parser, silent=True)).keys()) for lang, _ in used_languages } # Each language would also have the language independent bears. We remove # those and put them in the "All" category. all_lang_bears = bears_by_lang['All'] bears_by_lang = {lang: bears_by_lang[lang] - bears_by_lang['All'] for lang, _ in used_languages} bears_by_lang['All'] = all_lang_bears selected_bears = {} candidate_bears = copy.copy(bears_by_lang) to_propose_bears = {} REQUIRED_BEAR_LIST = IMPORTANT_BEAR_LIST if args.green_mode: from coala_quickstart.Constants import ( GREEN_MODE_COMPATIBLE_BEAR_LIST, GREEN_MODE_INCOMPATIBLE_BEAR_LIST, ) REQUIRED_BEAR_LIST = concatenate(IMPORTANT_BEAR_LIST, GREEN_MODE_COMPATIBLE_BEAR_LIST) NEW_REQUIRED_BEAR_LIST = {} for lang in REQUIRED_BEAR_LIST: NEW_REQUIRED_BEAR_LIST[lang] = set() for bear in REQUIRED_BEAR_LIST[lang]: if bear not in GREEN_MODE_INCOMPATIBLE_BEAR_LIST: NEW_REQUIRED_BEAR_LIST[lang].add(bear) REQUIRED_BEAR_LIST = NEW_REQUIRED_BEAR_LIST # Initialize selected_bears with REQUIRED_BEAR_LIST for lang, lang_bears in candidate_bears.items(): if lang_bears and lang in REQUIRED_BEAR_LIST: selected_bears[lang] = set() for bear in lang_bears: if bear.__name__ in REQUIRED_BEAR_LIST[lang]: selected_bears[lang].add(bear) if lang_bears and lang not in REQUIRED_BEAR_LIST and ( not args.green_mode): selected_bears[lang] = set(lang_bears) candidate_bears[lang] = set( [bear for bear in lang_bears if lang in selected_bears and bear not in selected_bears[lang]]) if args.green_mode: return selected_bears if not args.no_filter_by_capabilities: # Ask user for capablities user_selected_capabilities = set() if not args.non_interactive: user_selected_capabilities = ask_to_select_capabilties( list(ALL_CAPABILITIES), list(DEFAULT_CAPABILTIES), printer) desired_capabilities = ( user_selected_capabilities if user_selected_capabilities else DEFAULT_CAPABILTIES) # Filter bears based on capabilties for lang, lang_bears in candidate_bears.items(): # Eliminate bears which doesn't contain the desired capabilites capable_bears = get_bears_with_given_capabilities( lang_bears, desired_capabilities) candidate_bears[lang] = capable_bears lint_task_info = extracted_info.get('LintTaskInfo', []) project_dependency_info = extracted_info.get('ProjectDependencyInfo', []) # Use lint_task_info to propose bears to user. for lang, lang_bears in candidate_bears.items(): matching_linter_bears = get_matching_linter_bears( lang_bears, lint_task_info) to_propose_bears[lang] = matching_linter_bears # Use project_dependency_info to propose bears to user. for lang, lang_bears in candidate_bears.items(): matching_dep_bears = get_bears_with_matching_dependencies( lang_bears, project_dependency_info) if to_propose_bears.get(lang): to_propose_bears[lang].update(matching_dep_bears) else: to_propose_bears[lang] = matching_dep_bears for lang, lang_bears in to_propose_bears.items(): for bear in lang_bears: # get the non-optional settings of the bears settings = bear.get_non_optional_settings() if settings: user_input_reqd = False for setting in settings: if not is_autofill_possible( setting, lang, bear, extracted_info): user_input_reqd = True break if user_input_reqd: # Ask user to activate the bear if (args and not args.non_interactive and prompt_to_activate(bear, printer)): selected_bears[lang].add(bear) else: # All the non-optional settings can be filled automatically selected_bears[lang].add(bear) else: # no non-optional setting, select it right away! selected_bears[lang].add(bear) if not args.no_filter_by_capabilities: # capabilities satisfied till now satisfied_capabilities = get_bears_capabilties(selected_bears) remaining_capabilities = { lang: [cap for cap in desired_capabilities if lang in satisfied_capabilities and cap not in satisfied_capabilities[lang]] for lang in candidate_bears} filtered_bears = {} for lang, lang_bears in candidate_bears.items(): filtered_bears[lang] = get_bears_with_given_capabilities( lang_bears, remaining_capabilities[lang]) # Remove overlapping capabilty bears filtered_bears = remove_bears_with_conflicting_capabilties( filtered_bears) # Add to the selected_bears for lang, lang_bears in filtered_bears.items(): if not selected_bears.get(lang): selected_bears[lang] = lang_bears else: selected_bears[lang].update(lang_bears) return selected_bears
def filter_relevant_bears(used_languages, printer, arg_parser, extracted_info, log_printer=None): """ From the bear dict, filter the bears per relevant language. :param used_languages: A list of tuples with language name as the first element and percentage usage as the second element; sorted by percentage usage. :param printer: ``ConsolePrinter`` object to be used for console interactions. :param arg_parser: ``argparse.ArgumentParser`` object containing the arguments passed. :param extracted_info: list of information extracted from ``InfoExtractor`` classes. :return: A dict with language name as key and bear classes as value. """ args = arg_parser.parse_args() if arg_parser else None used_languages.append(('All', 100)) bears_by_lang = { lang: set( inverse_dicts(*get_filtered_bears( [lang], log_printer, arg_parser, silent=True)).keys()) for lang, _ in used_languages } # Each language would also have the language independent bears. We remove # those and put them in the "All" category. all_lang_bears = bears_by_lang['All'] bears_by_lang = { lang: bears_by_lang[lang] - bears_by_lang['All'] for lang, _ in used_languages } bears_by_lang['All'] = all_lang_bears selected_bears = {} candidate_bears = copy.copy(bears_by_lang) to_propose_bears = {} REQUIRED_BEAR_LIST = IMPORTANT_BEAR_LIST if args.green_mode: from coala_quickstart.Constants import ( GREEN_MODE_COMPATIBLE_BEAR_LIST, GREEN_MODE_INCOMPATIBLE_BEAR_LIST, ) REQUIRED_BEAR_LIST = concatenate(IMPORTANT_BEAR_LIST, GREEN_MODE_COMPATIBLE_BEAR_LIST) NEW_REQUIRED_BEAR_LIST = {} for lang in REQUIRED_BEAR_LIST: NEW_REQUIRED_BEAR_LIST[lang] = set() for bear in REQUIRED_BEAR_LIST[lang]: if bear not in GREEN_MODE_INCOMPATIBLE_BEAR_LIST: NEW_REQUIRED_BEAR_LIST[lang].add(bear) REQUIRED_BEAR_LIST = NEW_REQUIRED_BEAR_LIST # Initialize selected_bears with REQUIRED_BEAR_LIST for lang, lang_bears in candidate_bears.items(): if lang_bears and lang in REQUIRED_BEAR_LIST: selected_bears[lang] = set() for bear in lang_bears: if bear.__name__ in REQUIRED_BEAR_LIST[lang]: selected_bears[lang].add(bear) if lang_bears and lang not in REQUIRED_BEAR_LIST and ( not args.green_mode): selected_bears[lang] = set(lang_bears) candidate_bears[lang] = set([ bear for bear in lang_bears if lang in selected_bears and bear not in selected_bears[lang] ]) if args.green_mode: return selected_bears if not args.no_filter_by_capabilities: # Ask user for capablities user_selected_capabilities = set() if not args.non_interactive: user_selected_capabilities = ask_to_select_capabilities( list(ALL_CAPABILITIES), list(DEFAULT_CAPABILITIES), printer) desired_capabilities = (user_selected_capabilities if user_selected_capabilities else DEFAULT_CAPABILITIES) # Filter bears based on capabilities for lang, lang_bears in candidate_bears.items(): # Eliminate bears which doesn't contain the desired capabilities capable_bears = get_bears_with_given_capabilities( lang_bears, desired_capabilities) candidate_bears[lang] = capable_bears lint_task_info = extracted_info.get('LintTaskInfo', []) project_dependency_info = extracted_info.get('ProjectDependencyInfo', []) # Use lint_task_info to propose bears to user. for lang, lang_bears in candidate_bears.items(): matching_linter_bears = get_matching_linter_bears( lang_bears, lint_task_info) to_propose_bears[lang] = matching_linter_bears # Use project_dependency_info to propose bears to user. for lang, lang_bears in candidate_bears.items(): matching_dep_bears = get_bears_with_matching_dependencies( lang_bears, project_dependency_info) if to_propose_bears.get(lang): to_propose_bears[lang].update(matching_dep_bears) else: to_propose_bears[lang] = matching_dep_bears for lang, lang_bears in to_propose_bears.items(): for bear in lang_bears: # get the non-optional settings of the bears settings = bear.get_non_optional_settings() if settings: user_input_reqd = False for setting in settings: if not is_autofill_possible(setting, lang, bear, extracted_info): user_input_reqd = True break if user_input_reqd: # Ask user to activate the bear if (args and not args.non_interactive and prompt_to_activate(bear, printer)): selected_bears[lang].add(bear) else: # All the non-optional settings can be filled automatically selected_bears[lang].add(bear) else: # no non-optional setting, select it right away! selected_bears[lang].add(bear) if not args.no_filter_by_capabilities: # capabilities satisfied till now satisfied_capabilities = get_bears_capabilities(selected_bears) remaining_capabilities = { lang: [ cap for cap in desired_capabilities if lang in satisfied_capabilities and cap not in satisfied_capabilities[lang] ] for lang in candidate_bears } filtered_bears = {} for lang, lang_bears in candidate_bears.items(): filtered_bears[lang] = get_bears_with_given_capabilities( lang_bears, remaining_capabilities[lang]) # Remove overlapping capability bears filtered_bears = remove_bears_with_conflicting_capabilities( filtered_bears) # Add to the selected_bears for lang, lang_bears in filtered_bears.items(): if not selected_bears.get(lang): selected_bears[lang] = lang_bears else: selected_bears[lang].update(lang_bears) return selected_bears