diff options
author | Paul McGuire <ptmcg@users.noreply.github.com> | 2020-08-19 22:42:25 -0500 |
---|---|---|
committer | Paul McGuire <ptmcg@users.noreply.github.com> | 2020-08-19 22:42:25 -0500 |
commit | 508750e836c67f95856824b97d3893c6009dda8f (patch) | |
tree | da4b7981283c22d5e1da11e011bf5f9ef9dcf165 /pyparsing | |
parent | af90c6d42bfb1288c30d0e44046b0e2819ad54d6 (diff) | |
download | pyparsing-git-508750e836c67f95856824b97d3893c6009dda8f.tar.gz |
Convert SyntaxWarnings to ValueError and TypeError exceptions; change diagnostics to an enum, and add enable_diag(), disable_diag() and enable_all_warnings() methods; clean up pyparsing imports in test_unit.py
Diffstat (limited to 'pyparsing')
-rw-r--r-- | pyparsing/core.py | 205 | ||||
-rw-r--r-- | pyparsing/helpers.py | 20 |
2 files changed, 93 insertions, 132 deletions
diff --git a/pyparsing/core.py b/pyparsing/core.py index d8d3b9b..8c7728a 100644 --- a/pyparsing/core.py +++ b/pyparsing/core.py @@ -2,6 +2,7 @@ # core.py # from abc import ABC, abstractmethod +from enum import Enum, auto import string import copy import warnings @@ -78,8 +79,30 @@ class __compat__(__config_flags): class __diag__(__config_flags): + _type_desc = "diagnostic" + + warn_multiple_tokens_in_named_alternation = False + warn_ungrouped_named_tokens_in_collection = False + warn_name_set_on_empty_Forward = False + warn_on_parse_using_empty_Forward = False + warn_on_assignment_to_Forward = False + warn_on_multiple_string_args_to_oneof = False + warn_on_match_first_with_lshift_operator = False + enable_debug_on_named_expressions = False + + _all_names = [__ for __ in locals() if not __.startswith("_")] + _warning_names = [name for name in _all_names if name.startswith("warn")] + _debug_names = [name for name in _all_names if name.startswith("enable_debug")] + + @classmethod + def enable_all_warnings(cls): + for name in cls._warning_names: + cls.enable(name) + + +class Diagnostics(Enum): """ - Diagnostic configuration (all default to ``False``) + Diagnostic configuration (all default to disabled) - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results @@ -95,27 +118,40 @@ class __diag__(__config_flags): incorrectly called with multiple str arguments - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent calls to :class:`ParserElement.setName` + + Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`. + All warnings can be enabled by calling :class:`enable_all_warnings`. """ - _type_desc = "diagnostic" + warn_multiple_tokens_in_named_alternation = auto() + warn_ungrouped_named_tokens_in_collection = auto() + warn_name_set_on_empty_Forward = auto() + warn_on_parse_using_empty_Forward = auto() + warn_on_assignment_to_Forward = auto() + warn_on_multiple_string_args_to_oneof = auto() + warn_on_match_first_with_lshift_operator = auto() + enable_debug_on_named_expressions = auto() - warn_multiple_tokens_in_named_alternation = False - warn_ungrouped_named_tokens_in_collection = False - warn_name_set_on_empty_Forward = False - warn_on_parse_using_empty_Forward = False - warn_on_assignment_to_Forward = False - warn_on_multiple_string_args_to_oneof = False - warn_on_match_first_with_lshift_operator = False - enable_debug_on_named_expressions = False - _all_names = [__ for __ in locals() if not __.startswith("_")] - _warning_names = [name for name in _all_names if name.startswith("warn")] - _debug_names = [name for name in _all_names if name.startswith("enable_debug")] +def enable_diag(diag_enum): + """ + Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`). + """ + __diag__.enable(diag_enum.name) - @classmethod - def enable_all_warnings(cls): - for name in cls._warning_names: - cls.enable(name) + +def disable_diag(diag_enum): + """ + Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`). + """ + __diag__.disable(diag_enum.name) + + +def enable_all_warnings(): + """ + Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`). + """ + __diag__.enable_all_warnings() # hide abstract class @@ -1034,14 +1070,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return And([self, other]) def __radd__(self, other): @@ -1054,14 +1087,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return other + self def __sub__(self, other): @@ -1071,14 +1101,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return self + And._ErrorStop() + other def __rsub__(self, other): @@ -1088,14 +1115,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return other - self def __mul__(self, other): @@ -1197,14 +1221,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return MatchFirst([self, other]) def __ror__(self, other): @@ -1214,14 +1235,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return other | self def __xor__(self, other): @@ -1231,14 +1249,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return Or([self, other]) def __rxor__(self, other): @@ -1248,14 +1263,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return other ^ self def __and__(self, other): @@ -1265,14 +1277,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return Each([self, other]) def __rand__(self, other): @@ -1282,14 +1291,11 @@ class ParserElement(ABC): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): - warnings.warn( + raise TypeError( "Cannot combine element of type {} with ParserElement".format( type(other).__name__ - ), - SyntaxWarning, - stacklevel=2, + ) ) - return None return other & self def __invert__(self): @@ -1331,7 +1337,7 @@ class ParserElement(ABC): key = (key, key) if len(key) > 2: - warnings.warn( + raise TypeError( "only 1 or 2 index arguments supported ({}{})".format( key[:5], "... [{}]".format(len(key)) if len(key) > 5 else "" ) @@ -1879,12 +1885,7 @@ class Literal(Token): try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn( - "null string passed to Literal; use Empty() instead", - SyntaxWarning, - stacklevel=2, - ) - self.__class__ = Empty + raise ValueError("null string passed to Literal; use Empty() instead") self.errmsg = "Expected " + self.name self.mayReturnEmpty = False self.mayIndexError = False @@ -1952,11 +1953,7 @@ class Keyword(Token): try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn( - "null string passed to Keyword; use Empty() instead", - SyntaxWarning, - stacklevel=2, - ) + raise ValueError("null string passed to Keyword; use Empty() instead") self.errmsg = "Expected {} {}".format(type(self).__name__, self.name) self.mayReturnEmpty = False self.mayIndexError = False @@ -2408,11 +2405,7 @@ class Regex(Token): if isinstance(pattern, str_type): if not pattern: - warnings.warn( - "null string passed to Regex; use Empty() instead", - SyntaxWarning, - stacklevel=2, - ) + raise ValueError("null string passed to Regex; use Empty() instead") self.pattern = pattern self.flags = flags @@ -2421,12 +2414,9 @@ class Regex(Token): self.re = re.compile(self.pattern, self.flags) self.reString = self.pattern except sre_constants.error: - warnings.warn( - "invalid pattern ({!r}) passed to Regex".format(pattern), - SyntaxWarning, - stacklevel=2, + raise ValueError( + "invalid pattern ({!r}) passed to Regex".format(pattern) ) - raise elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): self.re = pattern @@ -2496,20 +2486,10 @@ class Regex(Token): # prints "<h1>main title</h1>" """ if self.asGroupList: - warnings.warn( - "cannot use sub() with Regex(asGroupList=True)", - SyntaxWarning, - stacklevel=2, - ) - raise SyntaxError() + raise TypeError("cannot use sub() with Regex(asGroupList=True)") if self.asMatch and callable(repl): - warnings.warn( - "cannot use sub() with a callable with Regex(asMatch=True)", - SyntaxWarning, - stacklevel=2, - ) - raise SyntaxError() + raise TypeError("cannot use sub() with a callable with Regex(asMatch=True)") if self.asMatch: @@ -2579,22 +2559,14 @@ class QuotedString(Token): # remove white space from quote chars - wont work anyway quoteChar = quoteChar.strip() if not quoteChar: - warnings.warn( - "quoteChar cannot be the empty string", SyntaxWarning, stacklevel=2 - ) - raise SyntaxError() + raise ValueError("quoteChar cannot be the empty string") if endQuoteChar is None: endQuoteChar = quoteChar else: endQuoteChar = endQuoteChar.strip() if not endQuoteChar: - warnings.warn( - "endQuoteChar cannot be the empty string", - SyntaxWarning, - stacklevel=2, - ) - raise SyntaxError() + raise ValueError("endQuoteChar cannot be the empty string") self.quoteChar = quoteChar self.quoteCharLen = len(quoteChar) @@ -2645,12 +2617,9 @@ class QuotedString(Token): self.reString = self.pattern self.re_match = self.re.match except sre_constants.error: - warnings.warn( - "invalid pattern {!r} passed to Regex".format(self.pattern), - SyntaxWarning, - stacklevel=2, + raise ValueError( + "invalid pattern {!r} passed to Regex".format(self.pattern) ) - raise self.errmsg = "Expected " + self.name self.mayIndexError = False @@ -4308,7 +4277,6 @@ class Forward(ParseElementEnhance): ): warnings.warn( "using '<<' operator with '|' is probably an error, use '<<='", - SyntaxWarning, stacklevel=2, ) ret = super().__or__(other) @@ -4319,7 +4287,7 @@ class Forward(ParseElementEnhance): if self.expr is None and __diag__.warn_on_assignment_to_Forward: warnings.warn_explicit( "Forward defined here but no expression attached later using '<<=' or '<<'", - SyntaxWarning, + UserWarning, filename=self.caller_frame.filename, lineno=self.caller_frame.lineno, ) @@ -4337,7 +4305,6 @@ class Forward(ParseElementEnhance): stacklevel = 2 warnings.warn( "Forward expression was never assigned a value, will not parse any input", - UserWarning, stacklevel=stacklevel, ) return super().parseImpl(instring, loc, doActions) diff --git a/pyparsing/helpers.py b/pyparsing/helpers.py index 57219b6..d013975 100644 --- a/pyparsing/helpers.py +++ b/pyparsing/helpers.py @@ -181,8 +181,8 @@ def oneOf(strs, caseless=False, useRegex=True, asKeyword=False): """ if isinstance(caseless, str_type): warnings.warn( - "More than one string argument passed to oneOf, pass " - "choices as a list or space-delimited string", + "More than one string argument passed to oneOf, pass" + " choices as a list or space-delimited string", stacklevel=2, ) @@ -201,11 +201,7 @@ def oneOf(strs, caseless=False, useRegex=True, asKeyword=False): elif isinstance(strs, Iterable): symbols = list(strs) else: - warnings.warn( - "Invalid argument to oneOf, expected string or iterable", - SyntaxWarning, - stacklevel=2, - ) + raise TypeError("Invalid argument to oneOf, expected string or iterable") if not symbols: return NoMatch() @@ -239,9 +235,7 @@ def oneOf(strs, caseless=False, useRegex=True, asKeyword=False): ) except sre_constants.error: warnings.warn( - "Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, - stacklevel=2, + "Exception creating Regex for oneOf, building MatchFirst", stacklevel=2 ) # last resort, just use MatchFirst @@ -600,9 +594,9 @@ def replaceHTMLEntity(t): return _htmlEntityMap.get(t.entity) -opAssoc = types.SimpleNamespace() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() +class opAssoc(Enum): + LEFT = auto() + RIGHT = auto() def infixNotation(baseExpr, opList, lpar=Suppress("("), rpar=Suppress(")")): |