def parse_options(cls, options): """Parse option values from Flake8's OptionManager.""" if options.builtins: cls.builtIns = cls.builtIns.union(options.builtins) cls.with_doctest = options.doctests included_files = [] for included_file in options.include_in_doctest: if included_file == '': continue if not included_file.startswith((os.sep, './', '~/')): included_files.append('./' + included_file) else: included_files.append(included_file) cls.include_in_doctest = utils.normalize_paths(included_files) excluded_files = [] for excluded_file in options.exclude_from_doctest: if excluded_file == '': continue if not excluded_file.startswith((os.sep, './', '~/')): excluded_files.append('./' + excluded_file) else: excluded_files.append(excluded_file) cls.exclude_from_doctest = utils.normalize_paths(excluded_files) inc_exc = set(cls.include_in_doctest).intersection( cls.exclude_from_doctest ) if inc_exc: raise ValueError('"%s" was specified in both the ' 'include-in-doctest and exclude-from-doctest ' 'options. You are not allowed to specify it in ' 'both for doctesting.' % inc_exc)
def parse_options(cls, options): """Parse option values from Flake8's OptionManager.""" if options.builtins: cls.builtIns = cls.builtIns.union(options.builtins) cls.with_doctest = options.doctests included_files = [] for included_file in options.include_in_doctest: if included_file == '': continue if not included_file.startswith((os.sep, './', '~/')): included_files.append('./' + included_file) else: included_files.append(included_file) cls.include_in_doctest = utils.normalize_paths(included_files) excluded_files = [] for excluded_file in options.exclude_from_doctest: if excluded_file == '': continue if not excluded_file.startswith((os.sep, './', '~/')): excluded_files.append('./' + excluded_file) else: excluded_files.append(excluded_file) cls.exclude_from_doctest = utils.normalize_paths(excluded_files) inc_exc = set(cls.include_in_doctest).intersection( cls.exclude_from_doctest) if inc_exc: raise ValueError('"%s" was specified in both the ' 'include-in-doctest and exclude-from-doctest ' 'options. You are not allowed to specify it in ' 'both for doctesting.' % inc_exc)
def parse_options(cls, options): """Parse option values from Flake8's OptionManager.""" if options.builtins: cls.builtIns = cls.builtIns.union(options.builtins) cls.with_doctest = options.doctests included_files = [] for included_file in options.include_in_doctest: if included_file == "": continue if not included_file.startswith((os.sep, "./", "~/")): included_files.append(f"./{included_file}") else: included_files.append(included_file) cls.include_in_doctest = utils.normalize_paths(included_files) excluded_files = [] for excluded_file in options.exclude_from_doctest: if excluded_file == "": continue if not excluded_file.startswith((os.sep, "./", "~/")): excluded_files.append(f"./{excluded_file}") else: excluded_files.append(excluded_file) cls.exclude_from_doctest = utils.normalize_paths(excluded_files) inc_exc = set(cls.include_in_doctest).intersection( cls.exclude_from_doctest) if inc_exc: raise ValueError(f"{inc_exc!r} was specified in both the " f"include-in-doctest and exclude-from-doctest " f"options. You are not allowed to specify it in " f"both for doctesting.")
def __init__(self, tree, file_tokens, filename): """Initialize the PyFlakes plugin with an AST tree and filename.""" filename = utils.normalize_paths(filename)[0] with_doctest = self.with_doctest included_by = [ include for include in self.include_in_doctest if include != "" and filename.startswith(include) ] if included_by: with_doctest = True for exclude in self.exclude_from_doctest: if exclude != "" and filename.startswith(exclude): with_doctest = False overlaped_by = [ include for include in included_by if include.startswith(exclude) ] if overlaped_by: with_doctest = True super(FlakesChecker, self).__init__( tree, filename=filename, withDoctest=with_doctest, file_tokens=file_tokens, )
def __init__(self, tree, filename): """Initialize the PyFlakes plugin with an AST tree and filename.""" filename = utils.normalize_paths(filename)[0] with_doctest = self.with_doctest included_by = [ include for include in self.include_in_doctest if include != '' and filename.startswith(include) ] if included_by: with_doctest = True for exclude in self.exclude_from_doctest: if exclude != '' and filename.startswith(exclude): with_doctest = False overlaped_by = [ include for include in included_by if include.startswith(exclude) ] if overlaped_by: with_doctest = True super(FlakesChecker, self).__init__(tree, filename, withDoctest=with_doctest)
def aggregate_options(manager, arglist=None, values=None): """Aggregate and merge CLI and config file options. :param flake8.option.manager.OptionManager manager: The instance of the OptionManager that we're presently using. :param list arglist: The list of arguments to pass to ``manager.parse_args``. In most cases this will be None so ``parse_args`` uses ``sys.argv``. This is mostly available to make testing easier. :param optparse.Values values: Previously parsed set of parsed options. :returns: Tuple of the parsed options and extra arguments returned by ``manager.parse_args``. :rtype: tuple(optparse.Values, list) """ # Get defaults from the option parser default_values, _ = manager.parse_args([], values=values) # Get original CLI values so we can find additional config file paths and # see if --config was specified. original_values, original_args = manager.parse_args(arglist) extra_config_files = utils.normalize_paths(original_values.append_config) # Make our new configuration file mergerator config_parser = config.MergedConfigParser( option_manager=manager, extra_config_files=extra_config_files, args=original_args, ) # Get the parsed config parsed_config = config_parser.parse(original_values.config, original_values.isolated) # Extend the default ignore value with the extended default ignore list, # registered by plugins. extended_default_ignore = manager.extended_default_ignore.copy() LOG.debug('Extended default ignore list: %s', list(extended_default_ignore)) extended_default_ignore.update(default_values.ignore) default_values.ignore = list(extended_default_ignore) LOG.debug('Merged default ignore list: %s', default_values.ignore) # Merge values parsed from config onto the default values returned for config_name, value in parsed_config.items(): dest_name = config_name # If the config name is somehow different from the destination name, # fetch the destination name from our Option if not hasattr(default_values, config_name): dest_name = config_parser.config_options[config_name].dest LOG.debug('Overriding default value of (%s) for "%s" with (%s)', getattr(default_values, dest_name, None), dest_name, value) # Override the default values with the config values setattr(default_values, dest_name, value) # Finally parse the command-line options return manager.parse_args(arglist, default_values)
def make_config_finder(self): """Make our ConfigFileFinder based on preliminary opts and args.""" if self.config_finder is None: extra_config_files = utils.normalize_paths( self.prelim_opts.append_config) self.config_finder = config.ConfigFileFinder( self.option_manager.program_name, self.prelim_args, extra_config_files)
def make_config_finder(self): """Make our ConfigFileFinder based on preliminary opts and args.""" if self.config_finder is None: extra_config_files = utils.normalize_paths( self.prelim_opts.append_config) self.config_finder = config.ConfigFileFinder( self.option_manager.program_name, self.prelim_args, extra_config_files, )
def get_local_plugins(config_finder, cli_config=None, isolated=False): """Get local plugins lists from config files. :param flake8.options.config.ConfigFileFinder config_finder: The config file finder to use. :param str cli_config: Value of --config when specified at the command-line. Overrides all other config files. :param bool isolated: Determines if we should parse configuration files at all or not. If running in isolated mode, we ignore all configuration files :returns: LocalPlugins namedtuple containing two lists of plugin strings, one for extension (checker) plugins and one for report plugins. :rtype: flake8.options.config.LocalPlugins """ local_plugins = LocalPlugins(extension=[], report=[], paths=[]) if isolated: LOG.debug("Refusing to look for local plugins in configuration" "files due to user-requested isolation") return local_plugins if cli_config: LOG.debug( 'Reading local plugins only from "%s" specified via ' "--config by the user", cli_config, ) config = config_finder.cli_config(cli_config) config_files = [cli_config] else: config, config_files = config_finder.local_configs_with_files() base_dirs = {os.path.dirname(cf) for cf in config_files} section = "%s:local-plugins" % config_finder.program_name for plugin_type in ["extension", "report"]: if config.has_option(section, plugin_type): local_plugins_string = config.get(section, plugin_type).strip() plugin_type_list = getattr(local_plugins, plugin_type) plugin_type_list.extend( utils.parse_comma_separated_list( local_plugins_string, regexp=utils.LOCAL_PLUGIN_LIST_RE)) if config.has_option(section, "paths"): raw_paths = utils.parse_comma_separated_list( config.get(section, "paths").strip()) norm_paths = [] # type: List[str] for base_dir in base_dirs: norm_paths.extend( path for path in utils.normalize_paths(raw_paths, parent=base_dir) if os.path.exists(path)) local_plugins.paths.extend(norm_paths) return local_plugins
def get_local_plugins(config_finder, cli_config=None, isolated=False): """Get local plugins lists from config files. :param flake8.options.config.ConfigFileFinder config_finder: The config file finder to use. :param str cli_config: Value of --config when specified at the command-line. Overrides all other config files. :param bool isolated: Determines if we should parse configuration files at all or not. If running in isolated mode, we ignore all configuration files :returns: LocalPlugins namedtuple containing two lists of plugin strings, one for extension (checker) plugins and one for report plugins. :rtype: flake8.options.config.LocalPlugins """ local_plugins = LocalPlugins(extension=[], report=[], paths=[]) if isolated: LOG.debug('Refusing to look for local plugins in configuration' 'files due to user-requested isolation') return local_plugins if cli_config: LOG.debug('Reading local plugins only from "%s" specified via ' '--config by the user', cli_config) config = config_finder.cli_config(cli_config) config_files = [cli_config] else: config, config_files = config_finder.local_configs_with_files() base_dirs = {os.path.dirname(cf) for cf in config_files} section = '%s:local-plugins' % config_finder.program_name for plugin_type in ['extension', 'report']: if config.has_option(section, plugin_type): local_plugins_string = config.get(section, plugin_type).strip() plugin_type_list = getattr(local_plugins, plugin_type) plugin_type_list.extend(utils.parse_comma_separated_list( local_plugins_string, regexp=utils.LOCAL_PLUGIN_LIST_RE, )) if config.has_option(section, 'paths'): raw_paths = utils.parse_comma_separated_list( config.get(section, 'paths').strip() ) norm_paths = [] for base_dir in base_dirs: norm_paths.extend( path for path in utils.normalize_paths(raw_paths, parent=base_dir) if os.path.exists(path) ) local_plugins.paths.extend(norm_paths) return local_plugins
def get_local_plugins(config_finder): """Get local plugins lists from config files. :param flake8.options.config.ConfigFileFinder config_finder: The config file finder to use. :returns: LocalPlugins namedtuple containing two lists of plugin strings, one for extension (checker) plugins and one for report plugins. :rtype: flake8.options.config.LocalPlugins """ local_plugins = LocalPlugins(extension=[], report=[], paths=[]) if config_finder.ignore_config_files: LOG.debug( "Refusing to look for local plugins in configuration" "files due to user-requested isolation" ) return local_plugins if config_finder.config_file: LOG.debug( 'Reading local plugins only from "%s" specified via ' "--config by the user", config_finder.config_file, ) config = config_finder.cli_config(config_finder.config_file) config_files = [config_finder.config_file] else: config, config_files = config_finder.local_configs_with_files() base_dirs = {os.path.dirname(cf) for cf in config_files} section = f"{config_finder.program_name}:local-plugins" for plugin_type in ["extension", "report"]: if config.has_option(section, plugin_type): local_plugins_string = config.get(section, plugin_type).strip() plugin_type_list = getattr(local_plugins, plugin_type) plugin_type_list.extend( utils.parse_comma_separated_list( local_plugins_string, regexp=utils.LOCAL_PLUGIN_LIST_RE ) ) if config.has_option(section, "paths"): raw_paths = utils.parse_comma_separated_list( config.get(section, "paths").strip() ) norm_paths: List[str] = [] for base_dir in base_dirs: norm_paths.extend( path for path in utils.normalize_paths(raw_paths, parent=base_dir) if os.path.exists(path) ) local_plugins.paths.extend(norm_paths) return local_plugins
def normalize(self, value: Any, *normalize_args: str) -> Any: """Normalize the value based on the option configuration.""" if self.comma_separated_list and isinstance(value, str): value = utils.parse_comma_separated_list(value) if self.normalize_paths: if isinstance(value, list): value = utils.normalize_paths(value, *normalize_args) else: value = utils.normalize_path(value, *normalize_args) return value
def __init__( self, program_name, extra_config_files=None, config_file=None, ignore_config_files=False, ): # type: (str, Optional[List[str]], Optional[str], bool) -> None """Initialize object to find config files. :param str program_name: Name of the current program (e.g., flake8). :param list extra_config_files: Extra configuration files specified by the user to read. :param str config_file: Configuration file override to only read configuraiton from. :param bool ignore_config_files: Determine whether to ignore configuration files or not. """ # The values of --append-config from the CLI if extra_config_files is None: extra_config_files = [] self.extra_config_files = utils.normalize_paths(extra_config_files) # The value of --config from the CLI. self.config_file = config_file # The value of --isolated from the CLI. self.ignore_config_files = ignore_config_files # Platform specific settings self.is_windows = sys.platform == "win32" self.xdg_home = os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")) # Look for '.<program_name>' files self.program_config = "." + program_name self.program_name = program_name # List of filenames to find in the local/project directory self.project_filenames = ("setup.cfg", "tox.ini", self.program_config) self.local_directory = os.path.abspath(os.curdir) # caches to avoid double-reading config files self._local_configs = None self._local_found_files = [] # type: List[str] self._user_config = None # fmt: off self._cli_configs = {} # type: Dict[str, configparser.RawConfigParser]
def _flake8_normalize(value, *args, **kwargs): comma_separated_list = kwargs.pop("comma_separated_list", False) normalize_paths = kwargs.pop("normalize_paths", False) if kwargs: raise TypeError("Unexpected keyword args: {}".format(kwargs)) if comma_separated_list and isinstance(value, utils.string_types): value = utils.parse_comma_separated_list(value) if normalize_paths: if isinstance(value, list): value = utils.normalize_paths(value, *args) else: value = utils.normalize_path(value, *args) return value
def _flake8_normalize(value: str, *args: str, **kwargs: bool) -> Union[str, List[str]]: comma_separated_list = kwargs.pop("comma_separated_list", False) normalize_paths = kwargs.pop("normalize_paths", False) if kwargs: raise TypeError(f"Unexpected keyword args: {kwargs}") ret: Union[str, List[str]] = value if comma_separated_list and isinstance(ret, str): ret = utils.parse_comma_separated_list(value) if normalize_paths: if isinstance(ret, str): ret = utils.normalize_path(ret, *args) else: ret = utils.normalize_paths(ret, *args) return ret
def _parse_config(content: str) -> Dict[str, Any]: config = toml.loads(content).get('tool', {}).get('flakehell', {}) config = dict(config) for section in ('plugins', 'exceptions'): if section in config: config[section] = dict(config[section]) if 'base' in config: paths = config['base'] if not isinstance(paths, list): paths = [paths] config = _merge_configs(read_config(*paths), config) if 'exclude' in config: config['exclude'] = normalize_paths(config['exclude']) return config
def _flake8_normalize(value, *args, **kwargs): # type: (str, *str, **bool) -> Union[str, List[str]] comma_separated_list = kwargs.pop("comma_separated_list", False) normalize_paths = kwargs.pop("normalize_paths", False) if kwargs: raise TypeError("Unexpected keyword args: {}".format(kwargs)) ret = value # type: Union[str, List[str]] if comma_separated_list and isinstance(ret, utils.string_types): ret = utils.parse_comma_separated_list(value) if normalize_paths: if isinstance(ret, utils.string_types): ret = utils.normalize_path(ret, *args) else: ret = utils.normalize_paths(ret, *args) return ret
def __init__( self, program_name: str, extra_config_files: Optional[List[str]] = None, config_file: Optional[str] = None, ignore_config_files: bool = False, ) -> None: """Initialize object to find config files. :param str program_name: Name of the current program (e.g., flake8). :param list extra_config_files: Extra configuration files specified by the user to read. :param str config_file: Configuration file override to only read configuration from. :param bool ignore_config_files: Determine whether to ignore configuration files or not. """ # The values of --append-config from the CLI if extra_config_files is None: extra_config_files = [] self.extra_config_files = utils.normalize_paths(extra_config_files) # The value of --config from the CLI. self.config_file = config_file # The value of --isolated from the CLI. self.ignore_config_files = ignore_config_files # User configuration file. self.program_name = program_name self.user_config_file = self._user_config_file(program_name) # List of filenames to find in the local/project directory self.project_filenames = ( "pyproject.toml", "setup.cfg", "tox.ini", f".{program_name}", ) self.local_directory = os.path.abspath(os.curdir)
def __init__(self, program_name, args, extra_config_files): # type: (str, List[str], List[str]) -> None """Initialize object to find config files. :param str program_name: Name of the current program (e.g., flake8). :param list args: The extra arguments passed on the command-line. :param list extra_config_files: Extra configuration files specified by the user to read. """ # The values of --append-config from the CLI extra_config_files = extra_config_files or [] self.extra_config_files = utils.normalize_paths(extra_config_files) # Platform specific settings self.is_windows = sys.platform == "win32" self.xdg_home = os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")) # Look for '.<program_name>' files self.program_config = "." + program_name self.program_name = program_name # List of filenames to find in the local/project directory self.project_filenames = ("setup.cfg", "tox.ini", self.program_config) self.local_directory = os.path.abspath(os.curdir) if not args: args = ["."] self.parent = self.tail = os.path.abspath(os.path.commonprefix(args)) # caches to avoid double-reading config files self._local_configs = None self._local_found_files = [] # type: List[str] self._user_config = None # fmt: off self._cli_configs = {} # type: Dict[str, configparser.RawConfigParser]
def test_normalize_paths(value, expected): """Verify we normalize comma-separated paths provided to the tool.""" assert utils.normalize_paths(value) == expected
def test_normalize_paths(value, expected): """Verify we normalizes a sequence of paths provided to the tool.""" assert utils.normalize_paths(value) == expected
def aggregate_options(manager, arglist=None, values=None): """Aggregate and merge CLI and config file options. :param flake8.option.manager.OptionManager manager: The instance of the OptionManager that we're presently using. :param list arglist: The list of arguments to pass to ``manager.parse_args``. In most cases this will be None so ``parse_args`` uses ``sys.argv``. This is mostly available to make testing easier. :param optparse.Values values: Previously parsed set of parsed options. :returns: Tuple of the parsed options and extra arguments returned by ``manager.parse_args``. :rtype: tuple(optparse.Values, list) """ # Get defaults from the option parser default_values, _ = manager.parse_args([], values=values) # Get original CLI values so we can find additional config file paths and # see if --config was specified. original_values, original_args = manager.parse_args(arglist) extra_config_files = utils.normalize_paths(original_values.append_config) # Make our new configuration file mergerator config_parser = config.MergedConfigParser( option_manager=manager, extra_config_files=extra_config_files, args=original_args, ) # Get the parsed config parsed_config = config_parser.parse(original_values.config, original_values.isolated) # Extend the default ignore value with the extended default ignore list, # registered by plugins. extended_default_ignore = manager.extended_default_ignore.copy() LOG.debug('Extended default ignore list: %s', list(extended_default_ignore)) extended_default_ignore.update(default_values.ignore) default_values.ignore = list(extended_default_ignore) LOG.debug('Merged default ignore list: %s', default_values.ignore) extended_default_select = manager.extended_default_select.copy() LOG.debug('Extended default select list: %s', list(extended_default_select)) default_values.extended_default_select = extended_default_select # Merge values parsed from config onto the default values returned for config_name, value in parsed_config.items(): dest_name = config_name # If the config name is somehow different from the destination name, # fetch the destination name from our Option if not hasattr(default_values, config_name): dest_name = config_parser.config_options[config_name].dest LOG.debug('Overriding default value of (%s) for "%s" with (%s)', getattr(default_values, dest_name, None), dest_name, value) # Override the default values with the config values setattr(default_values, dest_name, value) # Finally parse the command-line options return manager.parse_args(arglist, default_values)