summaryrefslogtreecommitdiff
path: root/pyparsing
diff options
context:
space:
mode:
authorPaul McGuire <ptmcg@users.noreply.github.com>2020-08-19 22:42:25 -0500
committerPaul McGuire <ptmcg@users.noreply.github.com>2020-08-19 22:42:25 -0500
commit508750e836c67f95856824b97d3893c6009dda8f (patch)
treeda4b7981283c22d5e1da11e011bf5f9ef9dcf165 /pyparsing
parentaf90c6d42bfb1288c30d0e44046b0e2819ad54d6 (diff)
downloadpyparsing-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.py205
-rw-r--r--pyparsing/helpers.py20
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(")")):