diff --git a/README.rst b/README.rst index 895b7c50..948f07a6 100644 --- a/README.rst +++ b/README.rst @@ -331,6 +331,14 @@ An example configuration for the sphinx checker is given below: } } +Exclude Sphinx deprecation warnings +----------------------------------- + +There is a special flag `--exclude-sphinx-deprecation` that lets the sphinx checker exclude +Sphinx deprecation warnings. These warnings match the following regular expression: +`RemovedInSphinx\\d+Warning`. Using this flag results in the same behavior as adding this +regex to the configuration file as value for the `exclude` key for the sphinx checker. + ======================= Issues and new Features diff --git a/src/mlx/warnings.py b/src/mlx/warnings.py index 93bb89b2..cd38a803 100644 --- a/src/mlx/warnings.py +++ b/src/mlx/warnings.py @@ -175,7 +175,7 @@ def config_parser_json(self, config): self.activate_checker(checker) checker.set_maximum(int(config[checker.name]['max'])) checker.set_minimum(int(config[checker.name]['min'])) - checker.set_exclude_patterns(config[checker.name].get("exclude")) + checker.add_patterns(config[checker.name].get("exclude"), checker.exclude_patterns) print("Config parsing for {name} completed".format(name=checker.name)) except KeyError as err: print("Incomplete config. Missing: {key}".format(key=err)) @@ -196,6 +196,8 @@ def warnings_wrapper(args): group2 = parser.add_argument_group('Configuration file with options') group2.add_argument('--config', dest='configfile', action='store', required=False, help='Config file in JSON format provides toggle of checkers and their limits') + group2.add_argument('--include-sphinx-deprecation', dest='include_sphinx_deprecation', action='store_true', + help="Sphinx checker will include warnings matching (RemovedInSphinx\\d+Warning) regex") parser.add_argument('-v', '--verbose', dest='verbose', action='store_true') parser.add_argument('--command', dest='command', action='store_true', help='Treat program arguments as command to execute to obtain data') @@ -230,6 +232,9 @@ def warnings_wrapper(args): warnings.set_maximum(args.maxwarnings) warnings.set_minimum(args.minwarnings) + if args.include_sphinx_deprecation and 'sphinx' in warnings.activated_checkers.keys(): + warnings.get_checker('sphinx').include_sphinx_deprecation() + if args.command: cmd = args.logfile if args.flags: diff --git a/src/mlx/warnings_checker.py b/src/mlx/warnings_checker.py index 32ebd0eb..d4a76c77 100644 --- a/src/mlx/warnings_checker.py +++ b/src/mlx/warnings_checker.py @@ -10,7 +10,7 @@ DOXYGEN_WARNING_REGEX = r"(?:((?:[/.]|[A-Za-z]).+?):(-?\d+):\s*([Ww]arning|[Ee]rror)|<.+>:-?\d+(?::\s*([Ww]arning|[Ee]rror))?): ((?!notes).+(?:(?!\s*(?:[Nn]otice|[Ww]arning|[Ee]rror): )[^/<\n][^:\n][^/\n].+)*)|\s*(\b[Nn]otice|\b[Ww]arning|\b[Ee]rror): (?!notes)(.+)\n?" doxy_pattern = re.compile(DOXYGEN_WARNING_REGEX) -SPHINX_WARNING_REGEX = r"(?m)^(?:(.+?:(?:\d+|None)?):?\s*)?(DEBUG|INFO|WARNING|ERROR|SEVERE|(?:\w+Sphinx\d+Warning)):\s*(.+)$" +SPHINX_WARNING_REGEX = r"(?m)^(?:(.+?:(?:\d+|None)?):?\s*)?(DEBUG|INFO|WARNING|ERROR|SEVERE):\s*(.+)$" sphinx_pattern = re.compile(SPHINX_WARNING_REGEX) PYTHON_XMLRUNNER_REGEX = r"(\s*(ERROR|FAILED) (\[\d+.\d\d\ds\]: \s*(.+)))\n?" @@ -33,6 +33,7 @@ def __init__(self, verbose=False): self.verbose = verbose self.reset() self.exclude_patterns = [] + self.include_patterns = [] def reset(self): ''' Reset function (resets min, max and counter values) ''' @@ -49,17 +50,18 @@ def check(self, content): ''' return - def set_exclude_patterns(self, exclude_regexes): - ''' Abstract setter function for the exclude patterns list[re.Pattern] + def add_patterns(self, regexes, pattern_container): + ''' Raises an Exception to explain that this feature is not available for the targeted checker Args: - exclude_regexes (list|None): List of regexes to ignore certain matched warning messages + regexes (list[str]|None): List of regexes to add + pattern_container (list[re.Pattern]): Target storage container for patterns Raises: - Exception: Feature of regexes to exclude warnings is only configurable for RegexChecker classes + Exception: Feature of regexes to include/exclude warnings is only configurable for the RegexChecker classes ''' - if exclude_regexes: - raise Exception("Feature of regexes to exclude warnings is not configurable for the {}." + if regexes: + raise Exception("Feature of regexes to include/exclude warnings is not configurable for the {}." .format(self.__class__.__name__)) def set_maximum(self, maximum): @@ -148,19 +150,19 @@ class RegexChecker(WarningsChecker): name = 'regex' pattern = None - def set_exclude_patterns(self, exclude_regexes): - ''' Setter function for the exclude patterns list[re.Pattern] + def add_patterns(self, regexes, pattern_container): + ''' Adds regexes as patterns to the specified container Args: - exclude_regexes (list|None): List of regexes to ignore certain matched warning messages + regexes (list[str]|None): List of regexes to add + pattern_container (list[re.Pattern]): Target storage container for patterns ''' - self.exclude_patterns = [] - if exclude_regexes: - if not isinstance(exclude_regexes, list): - raise TypeError("Excpected a list value for exclude key in configuration file; got {}" - .format(exclude_regexes.__class__.__name__)) - for regex in exclude_regexes: - self.exclude_patterns.append(re.compile(regex)) + if regexes: + if not isinstance(regexes, list): + raise TypeError("Expected a list value for exclude key in configuration file; got {}" + .format(regexes.__class__.__name__)) + for regex in regexes: + pattern_container.append(re.compile(regex)) def check(self, content): ''' Function for counting the number of warnings in a specific text @@ -177,7 +179,9 @@ def check(self, content): self.print_when_verbose(match_string) def _is_excluded(self, content): - ''' Checks if the specific text must be excluded based on the configured regexes for exclusion. + ''' Checks if the specific text must be excluded based on the configured regexes for exclusion and inclusion. + + Inclusion has priority over exclusion. Args: content (str): The content to parse @@ -185,17 +189,34 @@ def _is_excluded(self, content): Returns: bool: True for exclusion, False for inclusion ''' - for pattern in self.exclude_patterns: - if pattern.search(content): - self.print_when_verbose("Excluded {!r} because of configured regex {!r}" - .format(content, pattern.pattern)) - return True + matching_exclude_pattern = self._search_patterns(content, self.exclude_patterns) + if not self._search_patterns(content, self.include_patterns) and matching_exclude_pattern: + self.print_when_verbose("Excluded {!r} because of configured regex {!r}" + .format(content, matching_exclude_pattern)) + return True return False + @staticmethod + def _search_patterns(content, patterns): + ''' Returns the regex of the first pattern that matches specified content, None if nothing matches ''' + for pattern in patterns: + if pattern.search(content): + return pattern.pattern + return None + class SphinxChecker(RegexChecker): name = 'sphinx' pattern = sphinx_pattern + sphinx_deprecation_regex = r"(?m)^(?:(.+?:(?:\d+|None)?):?\s*)?(DEBUG|INFO|WARNING|ERROR|SEVERE|(?:\w+Sphinx\d+Warning)):\s*(.+)$" + sphinx_deprecation_regex_in_match = "RemovedInSphinx\\d+Warning" + + def include_sphinx_deprecation(self): + ''' + Adds the pattern for sphinx_deprecation_regex to the list patterns to include and alters the main pattern + ''' + self.pattern = re.compile(self.sphinx_deprecation_regex) + self.add_patterns([self.sphinx_deprecation_regex_in_match], self.include_patterns) class DoxyChecker(RegexChecker): diff --git a/tests/sphinx_double_deprecation_warning.txt b/tests/sphinx_double_deprecation_warning.txt new file mode 100644 index 00000000..1b3d5972 --- /dev/null +++ b/tests/sphinx_double_deprecation_warning.txt @@ -0,0 +1,4 @@ +/usr/local/lib/python3.7/dist-packages/sphinx/util/docutils.py:286: RemovedInSphinx30Warning: function based directive support is now deprecated. Use class based directive instead. + RemovedInSphinx30Warning) +/usr/local/lib/python3.7/dist-packages/sphinx_rtd_theme/search.html:20: RemovedInSphinx30Warning: To modify script_files in the theme is deprecated. Please insert a