def __getitem__(self, item): value = getattr(self.lang, item) if isinstance(value, (list, tuple)): value = Setting(item, ', '.join(escape(val, ',') for val in value)) elif isinstance(value, dict): value = Setting(item, ', '.join( escape(key, ':,') + ': ' + escape(val, ':,') for key, val in value.items())) else: value = Setting(item, str(value)) return value
def test_empty_list(self): self.section.append(Setting("format_str", "{origin}")) # Shouldn't attempt to format the string None and will fail badly if # its done wrong. print_results_formatted(None, self.section, [], None, None, None)
def test_bad_format(self): self.section.append(Setting("format_str", "{nonexistant}")) print_results_formatted(self.logger, self.section, [Result("1", "2")], None, None) self.assertRegex(''.join(log.message for log in self.logger.logs), ".*Unable to print.*")
def test_py2_version(self): self.check_validity(self.uut, ['print(123)'], valid=True) self.check_invalidity(self.uut, ['print 123']) self.section.append(Setting('python_version', '2.7')) self.check_validity(self.uut, ['print 123'], valid=True)
def test_no_value(self): self.section.append(Setting("default_actions", "")) self.assertEqual(get_default_actions(self.section), ({}, {}))
def test_good_format(self): self.section.append(Setting('format', '{origin}')) with retrieve_stdout() as stdout: print_results_formatted(self.logger, self.section, [Result('1', '2')], None, None) self.assertEqual(stdout.getvalue(), '1\n')
def setUp(self): self.section = Section('name') self.section.append(Setting('max_line_length', '79')) self.uut = PEP8Bear(self.section, Queue())
def test_get_config_dir(self): section = Section("default") section.append(Setting("files", "**", "/path/to/dir/config")) uut = TestBear(section, None) self.assertEqual(uut.get_config_dir(), abspath("/path/to/dir"))
def setUp(self): self.section = Section('name') self.uut = bear(self.section, queue.Queue()) for name, value in settings.items(): self.section.append(Setting(name, value))
def test_valid_link(self): content = test_file5.splitlines() self.section.append(Setting('check_links', True)) with prepare_file(content, None) as (file, fname): with execute_bear(self.uut, fname, file) as results: self.assertEqual(results, [])
def test_glob(self): self.uut = Setting('key', '.', origin=os.path.join('test (1)', 'somefile')) self.assertEqual(glob(self.uut), glob_escape(os.path.abspath('test (1)')))
def test_empty_key(self): with self.assertRaisesRegex( ValueError, 'An empty key is not allowed for a setting'): Setting('', 2)
def test_inherited_conversions(self): self.uut = Setting('key', ' 22\n', '.', strip_whitespaces=True) self.assertEqual(str(self.uut), '22') self.assertEqual(int(self.uut), 22) self.assertRaises(ValueError, bool, self.uut)
def test_str_list(self): self.uut = Setting('key', 'a, b, c') self.assertEqual(str_list(self.uut), ['a', 'b', 'c']) self.assertEqual(repr(str_list), 'typed_list(str)')
def test_language(self): self.uut = Setting('key', 'python 3.4') result = language(self.uut) self.assertIsInstance(result, Language) self.assertEqual(str(result), 'Python 3.4')
def setUp(self): self.project_dir = os.path.dirname(os.path.realpath(__file__)) self.log_printer = None self.section = Section('test') self.section.append(Setting('key', 'val'))
def test_bad_format(self): self.section.append(Setting("format_str", "{nonexistant}")) print_results_formatted(self.logger, self.section, [Result("1", "2")], None, None) self.assertRegex(self.printer.string, ".*Unable to print.*")
def test_line_length(self): self.check_validity(self.uut, ['a = 1 + 1 + 1 + 1 + 1 + 1 + 1']) self.section.append(Setting('max_line_length', '10')) self.check_validity(self.uut, ['a = 1 + 1 + 1 + 1 + 1 + 1 + 1'], valid=False)
def test_config_failure_use_spaces(self): self.section['checkstyle_configs'] = 'google' self.section.append(Setting('use_spaces', False)) with self.assertRaisesRegex(AssertionError, self.GOOGLE_VALUEERROR_RE): self.check_validity(self.uut, [], self.good_file)
def test_bad_format(self): self.section.append(Setting('format', '{nonexistant}')) print_results_formatted(self.logger, self.section, [Result('1', '2')], None, None) self.assertRegex(''.join(log.message for log in self.logger.logs), '.*Unable to print.*')
def test_config_failure_indent_size(self): self.section['checkstyle_configs'] = 'google' self.section.append(Setting('indent_size', 3)) with self.assertRaisesRegex(AssertionError, self.GOOGLE_VALUEERROR_RE): self.check_validity(self.uut, [], self.good_file)
def test_process_queues(self): ctrlq = queue.Queue() # Append custom controlling sequences. # Simulated process 1 ctrlq.put((CONTROL_ELEMENT.LOCAL, 1)) ctrlq.put((CONTROL_ELEMENT.LOCAL_FINISHED, None)) ctrlq.put((CONTROL_ELEMENT.GLOBAL, 1)) # Simulated process 2 ctrlq.put((CONTROL_ELEMENT.LOCAL, 2)) # Simulated process 1 ctrlq.put((CONTROL_ELEMENT.GLOBAL_FINISHED, None)) # Simulated process 2 ctrlq.put((CONTROL_ELEMENT.LOCAL_FINISHED, None)) ctrlq.put((CONTROL_ELEMENT.GLOBAL, 1)) ctrlq.put((CONTROL_ELEMENT.GLOBAL_FINISHED, None)) first_local = Result.from_values("o", "The first result.", file="f") second_local = Result.from_values("ABear", "The second result.", file="f", line=1) third_local = Result.from_values("ABear", "The second result.", file="f", line=4) fourth_local = Result.from_values("ABear", "Another result.", file="f", line=7) first_global = Result("o", "The one and only global result.") section = Section("") section.append(Setting('min_severity', "normal")) process_queues( [DummyProcess(control_queue=ctrlq) for i in range(3)], ctrlq, {1: [first_local, second_local, third_local, # The following are to be ignored Result('o', 'm', severity=RESULT_SEVERITY.INFO), Result.from_values("ABear", "u", "f", 2, 1), Result.from_values("ABear", "u", "f", 3, 1)], 2: [fourth_local, # The following are to be ignored HiddenResult("t", "c"), Result.from_values("ABear", "u", "f", 5, 1), Result.from_values("ABear", "u", "f", 6, 1)]}, {1: [first_global]}, {"f": ["first line # stop ignoring, invalid ignore range\n", "second line # ignore all\n", "third line\n", "fourth line # gnore shouldn't trigger without i!\n", "# Start ignoring ABear, BBear and CBear\n", "# Stop ignoring\n", "seventh"]}, lambda *args: self.queue.put(args[2]), section, None, self.log_printer, self.console_printer) self.assertEqual(self.queue.get(timeout=0), ([first_local, second_local, third_local])) self.assertEqual(self.queue.get(timeout=0), ([fourth_local])) self.assertEqual(self.queue.get(timeout=0), ([first_global])) self.assertEqual(self.queue.get(timeout=0), ([first_global]))
def test_inherited_conversions(self): self.uut = Setting("key", " 22\n", ".", True) self.assertEqual(str(self.uut), "22") self.assertEqual(int(self.uut), 22) self.assertRaises(ValueError, bool, self.uut)
def test_py2(self): self.check_validity(self.uut, ['print(123)'], valid=True) self.check_invalidity(self.uut, ['print 123']) self.section.append(Setting('language', 'Python 2')) self.check_validity(self.uut, ['print 123'], valid=True)
def __parse_lines(self, lines, origin): current_section_name = 'default' current_section = self.get_section(current_section_name) current_keys = [] no_section = True for line in lines: (section_name, keys, value, append, comment) = self.line_parser._parse(line) if comment != '': self.__add_comment(current_section, comment, origin) if section_name != '': no_section = False current_section_name = section_name current_section = self.get_section(current_section_name, True) current_keys = [] continue if comment == '' and keys == [] and value == '': self.__add_comment(current_section, '', origin) continue if keys != []: current_keys = keys for section_override, key in current_keys: if no_section: logging.warning('A setting does not have a section.' 'This is a deprecated feature please ' 'put this setting in a section defined' ' with `[<your-section-name]` in a ' 'configuration file.') if key == '': continue if section_override == '': current_section.add_or_create_setting( Setting( key, value, origin, to_append=append, # Start ignoring PEP8Bear, PycodestyleBear* # they fail to resolve this remove_empty_iter_elements=self. __remove_empty_iter_elements), # Stop ignoring allow_appending=(keys == [])) else: self.get_section( section_override, True ).add_or_create_setting( Setting( key, value, origin, to_append=append, # Start ignoring PEP8Bear, PycodestyleBear* # they fail to resolve this remove_empty_iter_elements=self. __remove_empty_iter_elements), # Stop ignoring allow_appending=(keys == []))
def test_get_config_dir(self): section = Section('default') section.append(Setting('files', '**', '/path/to/dir/config')) uut = Bear(section, {}) self.assertEqual(uut.get_config_dir(), abspath('/path/to/dir'))
def load_configuration(arg_list, log_printer, arg_parser=None): """ Parses the CLI args and loads the config file accordingly, taking default_coafile and the users .coarc into account. :param arg_list: The list of command line arguments. :param log_printer: The LogPrinter object for logging. :return: A tuple holding (log_printer: LogPrinter, sections: dict(str, Section), targets: list(str)). (Types indicated after colon.) """ cli_sections = parse_cli(arg_list=arg_list, arg_parser=arg_parser) check_conflicts(cli_sections) if ( bool(cli_sections["default"].get("find_config", "False")) and str(cli_sections["default"].get("config")) == ""): cli_sections["default"].add_or_create_setting( Setting("config", re.escape(find_user_config(os.getcwd())))) targets = [] # We don't want to store targets argument back to file, thus remove it for item in list(cli_sections["default"].contents.pop("targets", "")): targets.append(item.lower()) if bool(cli_sections["default"].get("no_config", "False")): sections = cli_sections else: default_sections = load_config_file(Constants.system_coafile, log_printer) user_sections = load_config_file( Constants.user_coafile, log_printer, silent=True) default_config = str( default_sections["default"].get("config", ".coafile")) user_config = str(user_sections["default"].get( "config", default_config)) config = os.path.abspath( str(cli_sections["default"].get("config", user_config))) try: save = bool(cli_sections["default"].get("save", "False")) except ValueError: # A file is deposited for the save parameter, means we want to save # but to a specific file. save = True coafile_sections = load_config_file(config, log_printer, silent=save) sections = merge_section_dicts(default_sections, user_sections) sections = merge_section_dicts(sections, coafile_sections) sections = merge_section_dicts(sections, cli_sections) for section in sections: if section != "default": sections[section].defaults = sections["default"] str_log_level = str(sections["default"].get("log_level", "")).upper() log_printer.log_level = LOG_LEVEL.str_dict.get(str_log_level, LOG_LEVEL.INFO) return sections, targets
def test_good_format(self): self.section.append(Setting("format_str", "{origin}")) with retrieve_stdout() as stdout: print_results_formatted(self.logger, self.section, [Result("1", "2")], None, None) self.assertEqual(stdout.getvalue(), "1\n")
def setUp(self): self.section = Section("default") self.section.append(Setting("config", '/path/to/file'))
def load_configuration(arg_list, log_printer=None, arg_parser=None, args=None, silent=False): """ Parses the CLI args and loads the config file accordingly, taking default_coafile and the users .coarc into account. :param arg_list: The list of CLI arguments. :param log_printer: The LogPrinter object for logging. :param arg_parser: An ``argparse.ArgumentParser`` instance used for parsing the CLI arguments. :param args: Alternative pre-parsed CLI arguments. :param silent: Whether or not to display warnings, ignored if ``save`` is enabled. :return: A tuple holding (log_printer: LogPrinter, sections: dict(str, Section), targets: list(str)). (Types indicated after colon.) """ cli_sections = parse_cli(arg_list=arg_list, arg_parser=arg_parser, args=args) check_conflicts(cli_sections) if ( bool(cli_sections['cli'].get('find_config', 'False')) and str(cli_sections['cli'].get('config')) == ''): cli_sections['cli'].add_or_create_setting( Setting('config', re.escape(find_user_config(os.getcwd())))) targets = [] # We don't want to store targets argument back to file, thus remove it for item in list(cli_sections['cli'].contents.pop('targets', '')): targets.append(item.lower()) if bool(cli_sections['cli'].get('no_config', 'False')): sections = cli_sections else: base_sections = load_config_file(Constants.system_coafile, silent=silent) user_sections = load_config_file( Constants.user_coafile, silent=True) default_config = str(base_sections['default'].get('config', '.coafile')) user_config = str(user_sections['default'].get( 'config', default_config)) config = os.path.abspath( str(cli_sections['cli'].get('config', user_config))) try: save = bool(cli_sections['cli'].get('save', 'False')) except ValueError: # A file is deposited for the save parameter, means we want to save # but to a specific file. save = True coafile_sections = load_config_file(config, silent=save or silent) sections = merge_section_dicts(base_sections, user_sections) sections = merge_section_dicts(sections, coafile_sections) if 'cli' in sections: logging.warning('\'cli\' is an internally reserved section name. ' 'It may have been generated into your coafile ' 'while running coala with `--save`. The settings ' 'in that section will inherit implicitly to all ' 'sections as defaults just like CLI args do. ' 'Please change the name of that section in your ' 'coafile to avoid any unexpected behavior.') sections = merge_section_dicts(sections, cli_sections) for name, section in list(sections.items()): section.set_default_section(sections) if name == 'default': if section.contents: logging.warning('Implicit \'Default\' section inheritance is ' 'deprecated. It will be removed soon. To ' 'silence this warning remove settings in the ' '\'Default\' section from your coafile. You ' 'can use dots to specify inheritance: the ' 'section \'all.python\' will inherit all ' 'settings from \'all\'.') sections['default'].update(sections['cli']) sections['default'].name = 'cli' sections['cli'] = sections['default'] del sections['default'] str_log_level = str(sections['cli'].get('log_level', '')).upper() logging.getLogger().setLevel(LOG_LEVEL.str_dict.get(str_log_level, LOG_LEVEL.INFO)) return sections, targets
def fill_section(section, acquire_settings, log_printer, bears, extracted_info): """ Retrieves needed settings from given bears and asks the user for missing values. If a setting is requested by several bears, the help text from the latest bear will be taken. :param section: A section containing available settings. Settings will be added if some are missing. :param acquire_settings: The method to use for requesting settings. It will get a parameter which is a dictionary with the settings name as key and a list containing a description in [0] and the names of the bears who need this setting in all following indexes. :param log_printer: The log printer for logging. :param bears: All bear classes or instances. :param extracted_info: A list of information extracted from the project files by ``InfoExtractor`` classes. :return: The new section. """ # Retrieve needed settings. prel_needed_settings = {} for bear in bears: needed = bear.get_non_optional_settings() for key in needed: if key in prel_needed_settings: prel_needed_settings[key]["bears"].append(bear.name) else: prel_needed_settings[key] = { "help_text": needed[key][0], "bears": [bear.name], "type": needed[key][1], } # Strip away existent settings. needed_settings = {} for setting, setting_info in prel_needed_settings.items(): if setting not in section: needed_settings[setting] = setting_info # Fill the settings with existing values if possible satisfied_settings = [] for setting in needed_settings.keys(): setting_bears = needed_settings[setting]["bears"] setting_help_text = needed_settings[setting]["help_text"] to_fill_values = list( autofill_value_if_possible(setting, section, setting_bears, extracted_info)) if len(set(to_fill_values)) == 1: section[setting] = to_fill_values[0] satisfied_settings.append(setting) elif len(to_fill_values) > 1: section[setting] = resolve_anomaly(setting, setting_help_text, setting_bears, to_fill_values) satisfied_settings.append(setting) else: pass for setting in satisfied_settings: del needed_settings[setting] # Get missing ones. if len(needed_settings) > 0: new_vals = acquire_settings(log_printer, needed_settings, section) for setting, help_text in new_vals.items(): section.append(Setting(setting, help_text)) return section