Change Log
==========
+Version 2.4.3 - November, 2019
+------------------------------
+- Fixed a bug in ParserElement.__eq__ that would for some parsers
+ create a recursion error at parser definition time. Thanks to
+ Michael Clerx for the assist. (Addresses issue #123)
+
+- Fixed bug in indentedBlock where a block that ended at the end
+ of the input string could cause pyaprsing to loop forever. Raised
+ as part of discussion on StackOverflow with geckos.
+
+- Backports from pyparsing 3.0.0:
+ . __diag__.enable_all_warnings()
+ . Fixed bug in PrecededBy which caused infinite recursion, issue #127
+ . support for using regex-compiled RE to construct Regex expressions
+
+
Version 2.4.2 - July, 2019
--------------------------
- Updated the shorthand notation that has been added for repetition
Metadata-Version: 1.2
Name: pyparsing
-Version: 2.4.2
+Version: 2.4.3
Summary: Python parsing module
Home-page: https://github.com/pyparsing/pyparsing/
Author: Paul McGuire
Author-email: ptmcg@users.sourceforge.net
License: MIT License
Download-URL: https://pypi.org/project/pyparsing/
-Description: UNKNOWN
+Description: PyParsing -- A Python Parsing Module
+ ====================================
+
+ |Build Status|
+
+ Introduction
+ ============
+
+ The pyparsing module is an alternative approach to creating and
+ executing simple grammars, vs. the traditional lex/yacc approach, or the
+ use of regular expressions. The pyparsing module provides a library of
+ classes that client code uses to construct the grammar directly in
+ Python code.
+
+ *[Since first writing this description of pyparsing in late 2003, this
+ technique for developing parsers has become more widespread, under the
+ name Parsing Expression Grammars - PEGs. See more information on PEGs at*
+ https://en.wikipedia.org/wiki/Parsing_expression_grammar *.]*
+
+ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form
+ ``"salutation, addressee!"``):
+
+ .. code:: python
+
+ from pyparsing import Word, alphas
+ greet = Word(alphas) + "," + Word(alphas) + "!"
+ hello = "Hello, World!"
+ print(hello, "->", greet.parseString(hello))
+
+ The program outputs the following::
+
+ Hello, World! -> ['Hello', ',', 'World', '!']
+
+ The Python representation of the grammar is quite readable, owing to the
+ self-explanatory class names, and the use of '+', '|' and '^' operator
+ definitions.
+
+ The parsed results returned from ``parseString()`` can be accessed as a
+ nested list, a dictionary, or an object with named attributes.
+
+ The pyparsing module handles some of the problems that are typically
+ vexing when writing text parsers:
+
+ - extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.)
+ - quoted strings
+ - embedded comments
+
+ The examples directory includes a simple SQL parser, simple CORBA IDL
+ parser, a config file parser, a chemical formula parser, and a four-
+ function algebraic notation parser, among many others.
+
+ Documentation
+ =============
+
+ There are many examples in the online docstrings of the classes
+ and methods in pyparsing. You can find them compiled into online docs
+ at https://pyparsing-docs.readthedocs.io/en/latest/. Additional
+ documentation resources and project info are listed in the online
+ GitHub wiki, at https://github.com/pyparsing/pyparsing/wiki. An
+ entire directory of examples is at
+ https://github.com/pyparsing/pyparsing/tree/master/examples.
+
+ License
+ =======
+
+ MIT License. See header of pyparsing.py
+
+ History
+ =======
+
+ See CHANGES file.
+
+ .. |Build Status| image:: https://travis-ci.org/pyparsing/pyparsing.svg?branch=master
+ :target: https://travis-ci.org/pyparsing/pyparsing
+
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
If an expression is not provided for the content argument, the nested
expression will capture all whitespace-delimited content between delimiters
-vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv as a list of separate values.
+ as a list of separate values.
Use the ignoreExpr argument to define expressions that may contain
opening or closing characters that should not be treated as opening
- ``replaceWith(replString)`` - returns a parse action that simply returns the
replString; useful when using transformString, or converting HTML entities, as in::
- nbsp = Literal(" ").setParseAction(replaceWith("<BLANK>"))
+ nbsp = Literal(" ").setParseAction( replaceWith("<BLANK>") )
- ``keepOriginalText``- (deprecated, use originalTextFor_ instead) restores any internal whitespace or suppressed
text within the tokens for a matched parse
expression. This is especially useful when defining expressions
for scanString or transformString applications.
-- ``withAttribute(*args, **kwargs)`` - helper to create a validating parse action to be used with start tags created
+- ``withAttribute( *args, **kwargs )`` - helper to create a validating parse action to be used with start tags created
with ``makeXMLTags`` or ``makeHTMLTags``. Use ``withAttribute`` to qualify a starting tag
with a required attribute value, to avoid false matches on common tags such as
``<TD>`` or ``<DIV>``.
Metadata-Version: 1.2
Name: pyparsing
-Version: 2.4.2
+Version: 2.4.3
Summary: Python parsing module
Home-page: https://github.com/pyparsing/pyparsing/
Author: Paul McGuire
Author-email: ptmcg@users.sourceforge.net
License: MIT License
Download-URL: https://pypi.org/project/pyparsing/
-Description: UNKNOWN
+Description: PyParsing -- A Python Parsing Module
+ ====================================
+
+ |Build Status|
+
+ Introduction
+ ============
+
+ The pyparsing module is an alternative approach to creating and
+ executing simple grammars, vs. the traditional lex/yacc approach, or the
+ use of regular expressions. The pyparsing module provides a library of
+ classes that client code uses to construct the grammar directly in
+ Python code.
+
+ *[Since first writing this description of pyparsing in late 2003, this
+ technique for developing parsers has become more widespread, under the
+ name Parsing Expression Grammars - PEGs. See more information on PEGs at*
+ https://en.wikipedia.org/wiki/Parsing_expression_grammar *.]*
+
+ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form
+ ``"salutation, addressee!"``):
+
+ .. code:: python
+
+ from pyparsing import Word, alphas
+ greet = Word(alphas) + "," + Word(alphas) + "!"
+ hello = "Hello, World!"
+ print(hello, "->", greet.parseString(hello))
+
+ The program outputs the following::
+
+ Hello, World! -> ['Hello', ',', 'World', '!']
+
+ The Python representation of the grammar is quite readable, owing to the
+ self-explanatory class names, and the use of '+', '|' and '^' operator
+ definitions.
+
+ The parsed results returned from ``parseString()`` can be accessed as a
+ nested list, a dictionary, or an object with named attributes.
+
+ The pyparsing module handles some of the problems that are typically
+ vexing when writing text parsers:
+
+ - extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.)
+ - quoted strings
+ - embedded comments
+
+ The examples directory includes a simple SQL parser, simple CORBA IDL
+ parser, a config file parser, a chemical formula parser, and a four-
+ function algebraic notation parser, among many others.
+
+ Documentation
+ =============
+
+ There are many examples in the online docstrings of the classes
+ and methods in pyparsing. You can find them compiled into online docs
+ at https://pyparsing-docs.readthedocs.io/en/latest/. Additional
+ documentation resources and project info are listed in the online
+ GitHub wiki, at https://github.com/pyparsing/pyparsing/wiki. An
+ entire directory of examples is at
+ https://github.com/pyparsing/pyparsing/tree/master/examples.
+
+ License
+ =======
+
+ MIT License. See header of pyparsing.py
+
+ History
+ =======
+
+ See CHANGES file.
+
+ .. |Build Status| image:: https://travis-ci.org/pyparsing/pyparsing.svg?branch=master
+ :target: https://travis-ci.org/pyparsing/pyparsing
+
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
test/karthik.ini
test/parsefiletest_input_file.txt
test/__pycache__/__init__.cpython-35.pyc
-test/__pycache__/jsonParserTests.cpython-35.pyc
\ No newline at end of file
+test/__pycache__/__init__.cpython-38.pyc
+test/__pycache__/jsonParserTests.cpython-35.pyc
+test/__pycache__/jsonParserTests.cpython-38.pyc
\ No newline at end of file
namespace class
"""
-__version__ = "2.4.2"
-__versionTime__ = "29 Jul 2019 02:58 UTC"
+__version__ = "2.4.3"
+__versionTime__ = "21 Oct 2019 23:43 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
__diag__.warn_on_multiple_string_args_to_oneof = False
__diag__.enable_debug_on_named_expressions = False
-# ~ sys.stderr.write("testing pyparsing module, version %s, %s\n" % (__version__, __versionTime__))
+def _enable_all_warnings():
+ __diag__.warn_multiple_tokens_in_named_alternation = True
+ __diag__.warn_ungrouped_named_tokens_in_collection = True
+ __diag__.warn_name_set_on_empty_Forward = True
+ __diag__.warn_on_multiple_string_args_to_oneof = True
+__diag__.enable_all_warnings = _enable_all_warnings
+
__all__ = ['__version__', '__versionTime__', '__author__', '__compat__', '__diag__',
'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation', 'locatedExpr', 'withClass',
'CloseMatch', 'tokenMap', 'pyparsing_common', 'pyparsing_unicode', 'unicode_set',
- 'conditionAsParseAction',
+ 'conditionAsParseAction', 're',
]
system_version = tuple(sys.version_info)[:3]
raise exc
def __eq__(self, other):
- if isinstance(other, ParserElement):
- if PY_3:
- self is other or super(ParserElement, self).__eq__(other)
- else:
- return self is other or vars(self) == vars(other)
+ if self is other:
+ return True
elif isinstance(other, basestring):
return self.matches(other)
- else:
- return super(ParserElement, self) == other
+ elif isinstance(other, ParserElement):
+ return vars(self) == vars(other)
+ return False
def __ne__(self, other):
return not (self == other)
If the given regex contains named groups (defined using ``(?P<name>...)``),
these will be preserved as named parse results.
+ If instead of the Python stdlib re module you wish to use a different RE module
+ (such as the `regex` module), you can replace it by either building your
+ Regex object with a compiled RE that was compiled using regex:
+
Example::
realnum = Regex(r"[+-]?\d+\.\d*")
date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)')
# ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")
+
+ # use regex module instead of stdlib re module to construct a Regex using
+ # a compiled regular expression
+ import regex
+ parser = pp.Regex(regex.compile(r'[0-9]'))
+
"""
- compiledREtype = type(re.compile("[A-Z]"))
def __init__(self, pattern, flags=0, asGroupList=False, asMatch=False):
"""The parameters ``pattern`` and ``flags`` are passed
to the ``re.compile()`` function as-is. See the Python
SyntaxWarning, stacklevel=2)
raise
- elif isinstance(pattern, Regex.compiledREtype):
+ elif hasattr(pattern, 'pattern') and hasattr(pattern, 'match'):
self.re = pattern
- self.pattern = self.reString = str(pattern)
+ self.pattern = self.reString = pattern.pattern
self.flags = flags
else:
- raise ValueError("Regex may only be constructed with a string or a compiled RE object")
+ raise TypeError("Regex may only be constructed with a string or a compiled RE object")
self.re_match = self.re.match
self.retreat = retreat
self.errmsg = "not preceded by " + str(expr)
self.skipWhitespace = False
+ self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None)))
def parseImpl(self, instring, loc=0, doActions=True):
if self.exact:
else:
# retreat specified a maximum lookbehind window, iterate
test_expr = self.expr + StringEnd()
- instring_slice = instring[:loc]
+ instring_slice = instring[max(0, loc - self.retreat):loc]
last_expr = ParseException(instring, loc, self.errmsg)
- for offset in range(1, min(loc, self.retreat + 1)):
+ for offset in range(1, min(loc, self.retreat + 1)+1):
try:
- _, ret = test_expr._parse(instring_slice, loc - offset)
+ # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:]))
+ _, ret = test_expr._parse(instring_slice, len(instring_slice) - offset)
except ParseBaseException as pbe:
last_expr = pbe
else:
break
else:
raise last_expr
- # return empty list of tokens, but preserve any defined results names
- del ret[:]
return loc, ret
# ~ print (strs, "->", "|".join([_escapeRegexChars(sym) for sym in symbols]))
try:
if len(symbols) == len("".join(symbols)):
- return Regex("[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols)).setName(' | '.join(symbols))
+ return Regex("[%s]" % "".join(_collapseAndEscapeRegexRangeChars(sym) for sym in symbols)).setName(' | '.join(symbols))
else:
return Regex("|".join(re.escape(sym) for sym in symbols)).setName(' | '.join(symbols))
except Exception:
if curCol < indentStack[-1]:
indentStack.pop()
- NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
+ NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress(), stopOn=StringEnd())
INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT')
PEER = Empty().setParseAction(checkPeerIndent).setName('')
UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT')
if indent:
smExpr = Group(Optional(NL)
+ INDENT
- + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))
+ + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL), stopOn=StringEnd())
+ UNDENT)
else:
smExpr = Group(Optional(NL)
- + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))
+ + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL), stopOn=StringEnd())
+ UNDENT)
smExpr.setFailAction(lambda a, b, c, d: reset_stack())
blockStatementExpr.ignore(_bslash + LineEnd())
[egg_info]
tag_build =
tag_date = 0
+tag_svn_revision = 0
from setuptools import setup
from pyparsing import __version__ as pyparsing_version
+# The directory containing this file
+README_name = __file__.replace("setup.py", "README.rst")
+
+# The text of the README file
+with open(README_name) as README:
+ pyparsing_main_doc = README.read()
+
modules = ["pyparsing",]
setup(# Distribution meta-data
name = "pyparsing",
version = pyparsing_version,
description = "Python parsing module",
+ long_description = pyparsing_main_doc,
author = "Paul McGuire",
author_email = "ptmcg@users.sourceforge.net",
url = "https://github.com/pyparsing/pyparsing/",
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
]
)
"Erroneous named results for {0}: expected {1}, got {2}".format(expr,
expected_dict,
result.asDict()))
+ # infinite loop test - from Issue #127
+ string_test = 'notworking'
+ # negs = pp.Or(['not', 'un'])('negs')
+ negs_pb = pp.PrecededBy('not', retreat=100)('negs_lb')
+ # negs_pb = pp.PrecededBy(negs, retreat=100)('negs_lb')
+ pattern = pp.Group(negs_pb + pp.Literal('working'))('main')
+
+ results = pattern.searchString(string_test)
+ try:
+ print_(results.dump())
+ except RecursionError:
+ self.assertTrue(False, "got maximum excursion limit exception")
+ else:
+ self.assertTrue(True, "got maximum excursion limit exception")
+
class CountedArrayTest(ParseTestCase):
def runTest(self):
BUFFER_OUTPUT = False
result = testRunner.run(makeTestSuiteTemp(testclasses))
+ sys.stdout.flush()
exit(0 if result.wasSuccessful() else 1)