summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@austin.rr.com>2020-10-24 23:34:49 -0500
committerptmcg <ptmcg@austin.rr.com>2020-10-24 23:34:49 -0500
commit3c495dbb0fb80cd1600984919a45a5c54baa2806 (patch)
treeb9409cc2461e316e45d2819a190d46e795501105
parent22027ba6256c8a12b08379c790875123f6a20e80 (diff)
downloadpyparsing-git-3c495dbb0fb80cd1600984919a45a5c54baa2806.tar.gz
ParseResults.List class to support returning an actual list from a parse action, plus aslist and asdict args to Group and Dict classes to emit native Python types instead of ParseResults; also update repr() output of ParseResults to include the type name instead of just a bare tuple.
-rw-r--r--CHANGES35
-rw-r--r--examples/jsonParser.py64
-rw-r--r--pyparsing/core.py26
-rw-r--r--pyparsing/results.py64
-rw-r--r--tests/json_parser_tests.py400
-rw-r--r--tests/test_unit.py541
6 files changed, 568 insertions, 562 deletions
diff --git a/CHANGES b/CHANGES
index f384eed..4334095 100644
--- a/CHANGES
+++ b/CHANGES
@@ -17,6 +17,30 @@ Version 3.0.0b1
consistent with Python calling conventions. All warnings warned by diagnostic
flags have been converted from `SyntaxWarnings` to `UserWarnings`.
+- To support parsers that are intended to generate native Python collection
+ types such as lists and dicts, the `Group` and `Dict` classes now accept an
+ additional boolean keyword argument `aslist` and `asdict` respectively. See
+ the `jsonParser.py` example in the `pyparsing/examples` source directory for
+ how to return types as `ParseResults` and as Python collection types, and the
+ distinctions in working with the different types.
+
+ In addition parse actions that must return a value of list type (which would
+ normally be converted internally to a ParseResults) can override this default
+ behavior by returning their list wrapped in the new `ParseResults.List` class:
+
+ # this parse action tries to return a list, but pyparsing
+ # will convert to a ParseResults
+ def return_as_list_but_still_get_parse_results(tokens):
+ return tokens.asList()
+
+ # this parse action returns the tokens as a list, and pyparsing will
+ # maintain its list type in the final parsing results
+ def return_as_list(tokens):
+ return ParseResults.List(tokens.asList())
+
+ This is the mechanism used internally by the `Group` class when defined
+ using `aslist=True`.
+
- API CHANGE
Added `cache_hit` keyword argument to debug actions. Previously, if packrat
parsing was enabled, the debug methods were not called in the event of cache
@@ -48,6 +72,17 @@ Version 3.0.0b1
has been skipped (was previously inconsistent, reported in Issue #244,
by Frank Goyens, thanks!).
+- Modified the repr() output for `ParseResults` to include the class
+ name as part of the output. This is to clarify for new pyparsing users
+ who misread the repr output as a tuple of a list and a dict. pyparsing
+ results will now read like:
+
+ ParseResults(['abc', 'def'], {'qty': 100}]
+
+ instead of just:
+
+ (['abc', 'def'], {'qty': 100}]
+
- Fixed bugs in Each when passed OneOrMore or ZeroOrMore expressions:
. first expression match could be enclosed in an extra nesting level
. out-of-order expressions now handled correctly if mixed with required
diff --git a/examples/jsonParser.py b/examples/jsonParser.py
index cf01318..6d6b1c2 100644
--- a/examples/jsonParser.py
+++ b/examples/jsonParser.py
@@ -41,6 +41,9 @@ def make_keyword(kwd_str, kwd_value):
return pp.Keyword(kwd_str).setParseAction(pp.replaceWith(kwd_value))
+# set to False to return ParseResults
+RETURN_PYTHON_COLLECTIONS = True
+
TRUE = make_keyword("true", True)
FALSE = make_keyword("false", False)
NULL = make_keyword("null", None)
@@ -52,14 +55,29 @@ jsonNumber = ppc.number()
jsonObject = pp.Forward().setName("jsonObject")
jsonValue = pp.Forward().setName("jsonValue")
+
jsonElements = pp.delimitedList(jsonValue)
-jsonArray = pp.Group(LBRACK + pp.Optional(jsonElements, []) + RBRACK)
-jsonValue << (
- jsonString | jsonNumber | pp.Group(jsonObject) | jsonArray | TRUE | FALSE | NULL
+# jsonArray = pp.Group(LBRACK + pp.Optional(jsonElements, []) + RBRACK)
+# jsonValue << (
+# jsonString | jsonNumber | pp.Group(jsonObject) | jsonArray | TRUE | FALSE | NULL
+# )
+# memberDef = pp.Group(jsonString + COLON + jsonValue).setName("jsonMember")
+
+jsonArray = pp.Group(
+ LBRACK + pp.Optional(jsonElements) + RBRACK, aslist=RETURN_PYTHON_COLLECTIONS
)
-memberDef = pp.Group(jsonString + COLON + jsonValue).setName("jsonMember")
+
+jsonValue << (jsonString | jsonNumber | jsonObject | jsonArray | TRUE | FALSE | NULL)
+
+memberDef = pp.Group(
+ jsonString + COLON + jsonValue, aslist=RETURN_PYTHON_COLLECTIONS
+).setName("jsonMember")
+
jsonMembers = pp.delimitedList(memberDef)
-jsonObject << pp.Dict(LBRACE + pp.Optional(jsonMembers) + RBRACE)
+# jsonObject << pp.Dict(LBRACE + pp.Optional(jsonMembers) + RBRACE)
+jsonObject << pp.Dict(
+ LBRACE + pp.Optional(jsonMembers) + RBRACE, asdict=RETURN_PYTHON_COLLECTIONS
+)
jsonComment = pp.cppStyleComment
jsonObject.ignore(jsonComment)
@@ -72,7 +90,7 @@ if __name__ == "__main__":
"title": "example glossary",
"GlossDiv": {
"title": "S",
- "GlossList":
+ "GlossList": [
{
"ID": "SGML",
"SortAs": "SGML",
@@ -91,22 +109,42 @@ if __name__ == "__main__":
"EmptyDict" : {},
"EmptyList" : []
}
+ ]
}
}
}
"""
results = jsonObject.parseString(testdata)
+
results.pprint()
+ if RETURN_PYTHON_COLLECTIONS:
+ from pprint import pprint
+
+ pprint(results)
+ else:
+ results.pprint()
print()
def testPrint(x):
print(type(x), repr(x))
- print(list(results.glossary.GlossDiv.GlossList.keys()))
- testPrint(results.glossary.title)
- testPrint(results.glossary.GlossDiv.GlossList.ID)
- testPrint(results.glossary.GlossDiv.GlossList.FalseValue)
- testPrint(results.glossary.GlossDiv.GlossList.Acronym)
- testPrint(results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2)
- testPrint(results.glossary.GlossDiv.GlossList.PrimesLessThan10)
+ if RETURN_PYTHON_COLLECTIONS:
+ results = results[0]
+ print(list(results["glossary"]["GlossDiv"]["GlossList"][0].keys()))
+ testPrint(results["glossary"]["title"])
+ testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["ID"])
+ testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["FalseValue"])
+ testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["Acronym"])
+ testPrint(
+ results["glossary"]["GlossDiv"]["GlossList"][0]["EvenPrimesGreaterThan2"]
+ )
+ testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["PrimesLessThan10"])
+ else:
+ print(list(results.glossary.GlossDiv.GlossList.keys()))
+ testPrint(results.glossary.title)
+ testPrint(results.glossary.GlossDiv.GlossList.ID)
+ testPrint(results.glossary.GlossDiv.GlossList.FalseValue)
+ testPrint(results.glossary.GlossDiv.GlossList.Acronym)
+ testPrint(results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2)
+ testPrint(results.glossary.GlossDiv.GlossList.PrimesLessThan10)
diff --git a/pyparsing/core.py b/pyparsing/core.py
index bf57c30..c05c93c 100644
--- a/pyparsing/core.py
+++ b/pyparsing/core.py
@@ -4457,6 +4457,9 @@ class Group(TokenConverter):
"""Converter to return the matched tokens as a list - useful for
returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions.
+ The optional ``aslist`` argument when set to True will return the
+ parsed tokens as a Python list instead of a pyparsing ParseResults.
+
Example::
ident = Word(alphas)
@@ -4471,12 +4474,20 @@ class Group(TokenConverter):
# -> ['fn', ['a', 'b', '100']]
"""
- def __init__(self, expr):
+ def __init__(self, expr, aslist=False):
super().__init__(expr)
self.saveAsList = True
+ self._asPythonList = aslist
def postParse(self, instring, loc, tokenlist):
- return [tokenlist]
+ if self._asPythonList:
+ return ParseResults.List(
+ tokenlist.asList()
+ if isinstance(tokenlist, ParseResults)
+ else list(tokenlist)
+ )
+ else:
+ return [tokenlist]
class Dict(TokenConverter):
@@ -4485,6 +4496,9 @@ class Dict(TokenConverter):
token in the expression as its key. Useful for tabular report
scraping when the first column can be used as a item key.
+ The optional ``asdict`` argument when set to True will return the
+ parsed tokens as a Python dict instead of a pyparsing ParseResults.
+
Example::
data_word = Word(alphas)
@@ -4519,9 +4533,10 @@ class Dict(TokenConverter):
See more examples at :class:`ParseResults` of accessing fields by results name.
"""
- def __init__(self, expr):
+ def __init__(self, expr, asdict=False):
super().__init__(expr)
self.saveAsList = True
+ self._asPythonDict = asdict
def postParse(self, instring, loc, tokenlist):
for i, tok in enumerate(tokenlist):
@@ -4544,10 +4559,7 @@ class Dict(TokenConverter):
else:
tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i)
- if self.resultsName:
- return [tokenlist]
- else:
- return tokenlist
+ return tokenlist if not self._asPythonDict else tokenlist.asDict()
class Suppress(TokenConverter):
diff --git a/pyparsing/results.py b/pyparsing/results.py
index cac1a3c..a30e919 100644
--- a/pyparsing/results.py
+++ b/pyparsing/results.py
@@ -80,6 +80,57 @@ class ParseResults:
"__weakref__",
]
+ class List(list):
+ """
+ Simple wrapper class to distinguish parsed list results that should be preserved
+ as actual Python lists, instead of being converted to :class:`ParseResults`:
+
+ LBRACK, RBRACK = map(pp.Suppress, "[]")
+ element = pp.Forward()
+ item = ppc.integer
+ element_list = LBRACK + pp.delimitedList(element) + RBRACK
+
+ # add parse actions to convert from ParseResults to actual Python collection types
+ def as_python_list(t):
+ return pp.ParseResults.List(t.asList())
+ element_list.addParseAction(as_python_list)
+
+ element <<= item | element_list
+
+ element.runTests('''
+ 100
+ [2,3,4]
+ [[2, 1],3,4]
+ [(2, 1),3,4]
+ (2,3,4)
+ ''', postParse=lambda s, r: (r[0], type(r[0])))
+
+ prints:
+
+ 100
+ (100, <class 'int'>)
+
+ [2,3,4]
+ ([2, 3, 4], <class 'list'>)
+
+ [[2, 1],3,4]
+ ([[2, 1], 3, 4], <class 'list'>)
+
+ (Used internally by :class:`Group` when `aslist=True`.)
+ """
+
+ def __new__(cls, contained=None):
+ if contained is None:
+ contained = []
+
+ if not isinstance(contained, list):
+ raise TypeError(
+ "{} may only be constructed with a list,"
+ " not {}".format(cls.__name__, type(contained).__name__)
+ )
+
+ return list.__new__(cls)
+
def __new__(cls, toklist=None, name=None, **kwargs):
if isinstance(toklist, ParseResults):
return toklist
@@ -87,11 +138,12 @@ class ParseResults:
self._name = None
self._parent = None
self._all_names = set()
+
if toklist is None:
toklist = []
- if isinstance(toklist, list):
- self._toklist = toklist[:]
- elif isinstance(toklist, _generator_type):
+ if isinstance(toklist, ParseResults.List):
+ self._toklist = [toklist[:]]
+ elif isinstance(toklist, (list, _generator_type)):
self._toklist = list(toklist)
else:
self._toklist = [toklist]
@@ -397,7 +449,7 @@ class ParseResults:
return other + self
def __repr__(self):
- return "({!r}, {})".format(self._toklist, self.asDict())
+ return "{}({!r}, {})".format(type(self).__name__, self._toklist, self.asDict())
def __str__(self):
return (
@@ -510,7 +562,7 @@ class ParseResults:
elif self._parent:
par = self._parent()
- def lookup(self, sub):
+ def find_in_parent(self, sub):
return next(
(
k
@@ -521,7 +573,7 @@ class ParseResults:
None,
)
- return lookup(self) if par else None
+ return find_in_parent(self) if par else None
elif (
len(self) == 1
and len(self._tokdict) == 1
diff --git a/tests/json_parser_tests.py b/tests/json_parser_tests.py
index 0b4fc4f..a5779ba 100644
--- a/tests/json_parser_tests.py
+++ b/tests/json_parser_tests.py
@@ -5,28 +5,29 @@
test1 = """
{
- "glossary": {
- "title": "example glossary",
- "GlossDiv": {
- "title": "S",
- "GlossList": [{
- "ID": "SGML",
- "SortAs": "SGML",
- "GlossTerm": "Standard Generalized Markup Language",
- "Acronym": "SGML",
- "LargestPrimeLessThan100": 97,
- "AvogadroNumber": 6.02E23,
- "EvenPrimesGreaterThan2": null,
- "PrimesLessThan10" : [2,3,5,7],
- "WMDsFound" : false,
- "IraqAlQaedaConnections" : null,
- "Abbrev": "ISO 8879:1986",
- "GlossDef":
-"A meta-markup language, used to create markup languages such as DocBook.",
- "GlossSeeAlso": ["GML", "XML", "markup"],
- "EmptyDict" : {},
- "EmptyList" : []
- }]
+ "glossary": {
+ "title": "example glossary",
+ "GlossDiv": {
+ "title": "S",
+ "GlossList": [
+ {
+ "ID": "SGML",
+ "SortAs": "SGML",
+ "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.",
+ "GlossSeeAlso": ["GML", "XML", "markup"],
+ "GlossTerm": "Standard Generalized Markup Language",
+ "Acronym": "SGML",
+ "LargestPrimeLessThan100": 97,
+ "AvogadroNumber": 6.02E23,
+ "EvenPrimesGreaterThan2": [],
+ "PrimesLessThan10" : [2,3,5,7],
+ "FermatTheoremInMargin" : false,
+ "MapRequiringFiveColors" : null,
+ "Abbrev": "ISO 8879:1986",
+ "EmptyDict" : {},
+ "EmptyList" : []
+ }
+ ]
}
}
}
@@ -45,6 +46,7 @@ test2 = """
}
}}
"""
+
test3 = """
{"widget": {
"debug": "on",
@@ -67,173 +69,173 @@ test4 = """
{
"servlet-name": "cofaxCDS",
"servlet-class": "org.cofax.cds.CDSServlet",
-/*
- Defines glossary variables that template designers
- can use across the site. You can add new
- variables to this set by creating a new init-param, with
- the param-name prefixed with "configGlossary:".
-*/
+ /*
+ Defines glossary variables that template designers
+ can use across the site. You can add new
+ variables to this set by creating a new init-param, with
+ the param-name prefixed with "configGlossary:".
+ */
"init-param": {
"configGlossary:installationAt": "Philadelphia, PA",
"configGlossary:adminEmail": "ksm@pobox.com",
"configGlossary:poweredBy": "Cofax",
"configGlossary:poweredByIcon": "/images/cofax.gif",
"configGlossary:staticPath": "/content/static",
-/*
- Defines the template loader and template processor
- classes. These are implementations of org.cofax.TemplateProcessor
- and org.cofax.TemplateLoader respectively. Simply create new
- implementation of these classes and set them here if the default
- implementations do not suit your needs. Leave these alone
- for the defaults.
-*/
+ /*
+ Defines the template loader and template processor
+ classes. These are implementations of org.cofax.TemplateProcessor
+ and org.cofax.TemplateLoader respectively. Simply create new
+ implementation of these classes and set them here if the default
+ implementations do not suit your needs. Leave these alone
+ for the defaults.
+ */
"templateProcessorClass": "org.cofax.WysiwygTemplate",
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
"templatePath": "templates",
"templateOverridePath": "",
-/*
- Defines the names of the default templates to look for
- when acquiring WYSIWYG templates. Leave these at their
- defaults for most usage.
-*/
+ /*
+ Defines the names of the default templates to look for
+ when acquiring WYSIWYG templates. Leave these at their
+ defaults for most usage.
+ */
"defaultListTemplate": "listTemplate.htm",
"defaultFileTemplate": "articleTemplate.htm",
-/*
- New! useJSP switches on JSP template processing.
- jspListTemplate and jspFileTemplate are the names
- of the default templates to look for when aquiring JSP
- templates. Cofax currently in production at KR has useJSP
- set to false, since our sites currently use WYSIWYG
- templating exclusively.
-*/
+ /*
+ New! useJSP switches on JSP template processing.
+ jspListTemplate and jspFileTemplate are the names
+ of the default templates to look for when aquiring JSP
+ templates. Cofax currently in production at KR has useJSP
+ set to false, since our sites currently use WYSIWYG
+ templating exclusively.
+ */
"useJSP": false,
"jspListTemplate": "listTemplate.jsp",
"jspFileTemplate": "articleTemplate.jsp",
-/*
- Defines the packageTag cache. This cache keeps
- Cofax from needing to interact with the database
- to look up packageTag commands.
-*/
+ /*
+ Defines the packageTag cache. This cache keeps
+ Cofax from needing to interact with the database
+ to look up packageTag commands.
+ */
"cachePackageTagsTrack": 200,
"cachePackageTagsStore": 200,
"cachePackageTagsRefresh": 60,
-/*
- Defines the template cache. Keeps Cofax from needing
- to go to the file system to load a raw template from
- the file system.
-*/
+ /*
+ Defines the template cache. Keeps Cofax from needing
+ to go to the file system to load a raw template from
+ the file system.
+ */
"cacheTemplatesTrack": 100,
"cacheTemplatesStore": 50,
"cacheTemplatesRefresh": 15,
-/*
- Defines the page cache. Keeps Cofax from processing
- templates to deliver to users.
-*/
+ /*
+ Defines the page cache. Keeps Cofax from processing
+ templates to deliver to users.
+ */
"cachePagesTrack": 200,
"cachePagesStore": 100,
"cachePagesRefresh": 10,
"cachePagesDirtyRead": 10,
-/*
- Defines the templates Cofax will use when
- being browsed by a search engine identified in
- searchEngineRobotsDb
-*/
+ /*
+ Defines the templates Cofax will use when
+ being browsed by a search engine identified in
+ searchEngineRobotsDb
+ */
"searchEngineListTemplate": "forSearchEnginesList.htm",
"searchEngineFileTemplate": "forSearchEngines.htm",
"searchEngineRobotsDb": "WEB-INF/robots.db",
-/*
- New! useDataStore enables/disables the Cofax database pool
-*/
+ /*
+ New! useDataStore enables/disables the Cofax database pool
+ */
"useDataStore": true,
-/*
- Defines the implementation of org.cofax.DataStore that Cofax
- will use. If this DataStore class does not suit your needs
- simply implement a new DataStore class and set here.
-*/
+ /*
+ Defines the implementation of org.cofax.DataStore that Cofax
+ will use. If this DataStore class does not suit your needs
+ simply implement a new DataStore class and set here.
+ */
"dataStoreClass": "org.cofax.SqlDataStore",
-/*
- Defines the implementation of org.cofax.Redirection that
- Cofax will use. If this Redirection class does not suit
- your needs simply implenet a new Redirection class
- and set here.
-*/
+ /*
+ Defines the implementation of org.cofax.Redirection that
+ Cofax will use. If this Redirection class does not suit
+ your needs simply implenet a new Redirection class
+ and set here.
+ */
"redirectionClass": "org.cofax.SqlRedirection",
-/*
- Defines the data store name. Keep this at the default
-*/
+ /*
+ Defines the data store name. Keep this at the default
+ */
"dataStoreName": "cofax",
-/*
- Defines the JDBC driver that Cofax's database pool will use
-*/
+ /*
+ Defines the JDBC driver that Cofax's database pool will use
+ */
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
-/*
- Defines the JDBC connection URL to connect to the database
-*/
+ /*
+ Defines the JDBC connection URL to connect to the database
+ */
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
-/*
- Defines the user name to connect to the database
-*/
+ /*
+ Defines the user name to connect to the database
+ */
"dataStoreUser": "sa",
-/*
- Defines the password to connect to the database
-*/
+ /*
+ Defines the password to connect to the database
+ */
"dataStorePassword": "dataStoreTestQuery",
-/*
- A query that will run to test the validity of the
- connection in the pool.
-*/
+ /*
+ A query that will run to test the validity of the
+ connection in the pool.
+ */
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
-/*
- A log file to print out database information
-*/
+ /*
+ A log file to print out database information
+ */
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
-/*
- The number of connection to initialize on startup
-*/
+ /*
+ The number of connection to initialize on startup
+ */
"dataStoreInitConns": 10,
-/*
- The maximum number of connection to use in the pool
-*/
+ /*
+ The maximum number of connection to use in the pool
+ */
"dataStoreMaxConns": 100,
-/*
- The number of times a connection will be utilized from the
- pool before disconnect
-*/
+ /*
+ The number of times a connection will be utilized from the
+ pool before disconnect
+ */
"dataStoreConnUsageLimit": 100,
-/*
- The level of information to print to the log
-*/
+ /*
+ The level of information to print to the log
+ */
"dataStoreLogLevel": "debug",
-/*
- The maximum URL length allowable by the CDS Servlet
- Helps to prevent hacking
-*/
+ /*
+ The maximum URL length allowable by the CDS Servlet
+ Helps to prevent hacking
+ */
"maxUrlLength": 500}},
-/*
- Defines the Email Servlet
-*/
+ /*
+ Defines the Email Servlet
+ */
{
"servlet-name": "cofaxEmail",
"servlet-class": "org.cofax.cds.EmailServlet",
"init-param": {
-/*
- The mail host to be used by the mail servlet
-*/
+ /*
+ The mail host to be used by the mail servlet
+ */
"mailHost": "mail1",
-/*
- An override
-*/
+ /*
+ An override
+ */
"mailHostOverride": "mail2"}},
-/*
- Defines the Admin Servlet - used to refresh cache on
- demand and see statistics
-*/
+ /*
+ Defines the Admin Servlet - used to refresh cache on
+ demand and see statistics
+ */
{
"servlet-name": "cofaxAdmin",
"servlet-class": "org.cofax.cds.AdminServlet"},
-/*
- Defines the File Servlet - used to display files like Apache
-*/
+ /*
+ Defines the File Servlet - used to display files like Apache
+ */
{
"servlet-name": "fileServlet",
"servlet-class": "org.cofax.cds.FileServlet"},
@@ -241,87 +243,87 @@ test4 = """
"servlet-name": "cofaxTools",
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
"init-param": {
-/*
- Path to the template folder relative to the tools tomcat installation.
-*/
+ /*
+ Path to the template folder relative to the tools tomcat installation.
+ */
"templatePath": "toolstemplates/",
-/*
- Logging boolean 1 = on, 0 = off
-*/
+ /*
+ Logging boolean 1 = on, 0 = off
+ */
"log": 1,
-/*
- Location of log. If empty, log will be written System.out
-*/
+ /*
+ Location of log. If empty, log will be written System.out
+ */
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
-/*
- Max size of log in BITS. If size is empty, no limit to log.
- If size is defined, log will be overwritten upon reaching defined size.
-*/
+ /*
+ Max size of log in BITS. If size is empty, no limit to log.
+ If size is defined, log will be overwritten upon reaching defined size.
+ */
"logMaxSize": "",
-/*
- DataStore logging boolean 1 = on, 0 = off
-*/
+ /*
+ DataStore logging boolean 1 = on, 0 = off
+ */
"dataLog": 1,
-/*
- DataStore location of log. If empty, log will be written System.out
-*/
+ /*
+ DataStore location of log. If empty, log will be written System.out
+ */
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
-/*
- Max size of log in BITS. If size is empty, no limit to log.
- If size is defined, log will be overwritten upon reaching defined size.
-*/
+ /*
+ Max size of log in BITS. If size is empty, no limit to log.
+ If size is defined, log will be overwritten upon reaching defined size.
+ */
"dataLogMaxSize": "",
-/*
- Http string relative to server root to call for page cache
- removal to Cofax Servlet.
-*/
+ /*
+ Http string relative to server root to call for page cache
+ removal to Cofax Servlet.
+ */
"removePageCache": "/content/admin/remove?cache=pages&id=",
-/*
- Http string relative to server root to call for template
- cache removal to Cofax Servlet.
-*/
+ /*
+ Http string relative to server root to call for template
+ cache removal to Cofax Servlet.
+ */
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
-/*
- Location of folder from root of drive that will be used for
- ftp transfer from beta server or user hard drive to live servers.
- Note that Edit Article will not function without this variable
- set correctly. MultiPart request relies upon access to this folder.
-*/
+ /*
+ Location of folder from root of drive that will be used for
+ ftp transfer from beta server or user hard drive to live servers.
+ Note that Edit Article will not function without this variable
+ set correctly. MultiPart request relies upon access to this folder.
+ */
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
-/*
- Defines whether the Server should look in another path for
- config files or variables.
-*/
+ /*
+ Defines whether the Server should look in another path for
+ config files or variables.
+ */
"lookInContext": 1,
-/*
- Number of the ID of the top level administration group in tblPermGroups.
-*/
+ /*
+ Number of the ID of the top level administration group in tblPermGroups.
+ */
"adminGroupID": 4,
-/*
- Is the tools app running on the 'beta server'.
-*/
+ /*
+ Is the tools app running on the 'beta server'.
+ */
"betaServer": true}}],
"servlet-mapping": {
-/*
- URL mapping for the CDS Servlet
-*/
+ /*
+ URL mapping for the CDS Servlet
+ */
"cofaxCDS": "/",
-/*
- URL mapping for the Email Servlet
-*/
+ /*
+ URL mapping for the Email Servlet
+ */
"cofaxEmail": "/cofaxutil/aemail/*",
-/*
- URL mapping for the Admin servlet
-*/
+ /*
+ URL mapping for the Admin servlet
+ */
"cofaxAdmin": "/admin/*",
-/*
- URL mapping for the Files servlet
-*/
+ /*
+ URL mapping for the Files servlet
+ */
"fileServlet": "/static/*",
"cofaxTools": "/tools/*"},
-/*
- New! The cofax taglib descriptor file
-*/
+ /*
+ New! The cofax taglib descriptor file
+ */
"taglib": {
"taglib-uri": "cofax.tld",
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
diff --git a/tests/test_unit.py b/tests/test_unit.py
index 4897d97..ffec86a 100644
--- a/tests/test_unit.py
+++ b/tests/test_unit.py
@@ -400,346 +400,213 @@ class Test2_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
def testParseJSONData(self):
expected = [
- [
- [
- "glossary",
- [
- ["title", "example glossary"],
- [
- "GlossDiv",
- [
- ["title", "S"],
- [
- "GlossList",
- [
- [
- ["ID", "SGML"],
- ["SortAs", "SGML"],
- [
- "GlossTerm",
- "Standard Generalized Markup Language",
- ],
- ["Acronym", "SGML"],
- ["LargestPrimeLessThan100", 97],
- ["AvogadroNumber", 6.02e23],
- ["EvenPrimesGreaterThan2", None],
- ["PrimesLessThan10", [2, 3, 5, 7]],
- ["WMDsFound", False],
- ["IraqAlQaedaConnections", None],
- ["Abbrev", "ISO 8879:1986"],
- [
- "GlossDef",
- "A meta-markup language, used to create markup languages such as "
- "DocBook.",
- ],
- ["GlossSeeAlso", ["GML", "XML", "markup"]],
- ["EmptyDict", []],
- ["EmptyList", [[]]],
- ]
- ],
- ],
- ],
- ],
- ],
- ]
- ],
- [
- [
- "menu",
- [
- ["id", "file"],
- ["value", "File:"],
- [
- "popup",
- [
- [
- "menuitem",
- [
- [
- ["value", "New"],
- ["onclick", "CreateNewDoc()"],
- ],
- [["value", "Open"], ["onclick", "OpenDoc()"]],
- [["value", "Close"], ["onclick", "CloseDoc()"]],
- ],
- ]
- ],
- ],
- ],
- ]
- ],
- [
- [
- "widget",
- [
- ["debug", "on"],
- [
- "window",
- [
- ["title", "Sample Konfabulator Widget"],
- ["name", "main_window"],
- ["width", 500],
- ["height", 500],
- ],
- ],
- [
- "image",
- [
- ["src", "Images/Sun.png"],
- ["name", "sun1"],
- ["hOffset", 250],
- ["vOffset", 250],
- ["alignment", "center"],
- ],
- ],
- [
- "text",
- [
- ["data", "Click Here"],
- ["size", 36],
- ["style", "bold"],
- ["name", "text1"],
- ["hOffset", 250],
- ["vOffset", 100],
- ["alignment", "center"],
- [
- "onMouseUp",
- "sun1.opacity = (sun1.opacity / 100) * 90;",
- ],
- ],
- ],
- ],
- ]
- ],
- [
- [
- "web-app",
- [
- [
- "servlet",
- [
- [
- ["servlet-name", "cofaxCDS"],
- ["servlet-class", "org.cofax.cds.CDSServlet"],
- [
- "init-param",
- [
- [
- "configGlossary:installationAt",
- "Philadelphia, PA",
- ],
- [
- "configGlossary:adminEmail",
- "ksm@pobox.com",
- ],
- ["configGlossary:poweredBy", "Cofax"],
- [
- "configGlossary:poweredByIcon",
- "/images/cofax.gif",
- ],
- [
- "configGlossary:staticPath",
- "/content/static",
- ],
- [
- "templateProcessorClass",
- "org.cofax.WysiwygTemplate",
- ],
- [
- "templateLoaderClass",
- "org.cofax.FilesTemplateLoader",
- ],
- ["templatePath", "templates"],
- ["templateOverridePath", ""],
- ["defaultListTemplate", "listTemplate.htm"],
- [
- "defaultFileTemplate",
- "articleTemplate.htm",
- ],
- ["useJSP", False],
- ["jspListTemplate", "listTemplate.jsp"],
- ["jspFileTemplate", "articleTemplate.jsp"],
- ["cachePackageTagsTrack", 200],
- ["cachePackageTagsStore", 200],
- ["cachePackageTagsRefresh", 60],
- ["cacheTemplatesTrack", 100],
- ["cacheTemplatesStore", 50],
- ["cacheTemplatesRefresh", 15],
- ["cachePagesTrack", 200],
- ["cachePagesStore", 100],
- ["cachePagesRefresh", 10],
- ["cachePagesDirtyRead", 10],
- [
- "searchEngineListTemplate",
- "forSearchEnginesList.htm",
- ],
- [
- "searchEngineFileTemplate",
- "forSearchEngines.htm",
- ],
- [
- "searchEngineRobotsDb",
- "WEB-INF/robots.db",
- ],
- ["useDataStore", True],
- [
- "dataStoreClass",
- "org.cofax.SqlDataStore",
- ],
- [
- "redirectionClass",
- "org.cofax.SqlRedirection",
- ],
- ["dataStoreName", "cofax"],
- [
- "dataStoreDriver",
- "com.microsoft.jdbc.sqlserver.SQLServerDriver",
- ],
- [
- "dataStoreUrl",
- "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
- ],
- ["dataStoreUser", "sa"],
- ["dataStorePassword", "dataStoreTestQuery"],
- [
- "dataStoreTestQuery",
- "SET NOCOUNT ON;select test='test';",
- ],
- [
- "dataStoreLogFile",
- "/usr/local/tomcat/logs/datastore.log",
- ],
- ["dataStoreInitConns", 10],
- ["dataStoreMaxConns", 100],
- ["dataStoreConnUsageLimit", 100],
- ["dataStoreLogLevel", "debug"],
- ["maxUrlLength", 500],
- ],
- ],
- ],
- [
- ["servlet-name", "cofaxEmail"],
- ["servlet-class", "org.cofax.cds.EmailServlet"],
- [
- "init-param",
- [
- ["mailHost", "mail1"],
- ["mailHostOverride", "mail2"],
- ],
- ],
- ],
- [
- ["servlet-name", "cofaxAdmin"],
- ["servlet-class", "org.cofax.cds.AdminServlet"],
- ],
- [
- ["servlet-name", "fileServlet"],
- ["servlet-class", "org.cofax.cds.FileServlet"],
- ],
- [
- ["servlet-name", "cofaxTools"],
- [
- "servlet-class",
- "org.cofax.cms.CofaxToolsServlet",
- ],
- [
- "init-param",
- [
- ["templatePath", "toolstemplates/"],
- ["log", 1],
- [
- "logLocation",
- "/usr/local/tomcat/logs/CofaxTools.log",
- ],
- ["logMaxSize", ""],
- ["dataLog", 1],
- [
- "dataLogLocation",
- "/usr/local/tomcat/logs/dataLog.log",
- ],
- ["dataLogMaxSize", ""],
- [
- "removePageCache",
- "/content/admin/remove?cache=pages&id=",
- ],
- [
- "removeTemplateCache",
- "/content/admin/remove?cache=templates&id=",
- ],
- [
- "fileTransferFolder",
- "/usr/local/tomcat/webapps/content/fileTransferFolder",
- ],
- ["lookInContext", 1],
- ["adminGroupID", 4],
- ["betaServer", True],
- ],
- ],
- ],
- ],
- ],
- [
- "servlet-mapping",
- [
- ["cofaxCDS", "/"],
- ["cofaxEmail", "/cofaxutil/aemail/*"],
- ["cofaxAdmin", "/admin/*"],
- ["fileServlet", "/static/*"],
- ["cofaxTools", "/tools/*"],
- ],
- ],
- [
- "taglib",
- [
- ["taglib-uri", "cofax.tld"],
- ["taglib-location", "/WEB-INF/tlds/cofax.tld"],
- ],
+ {
+ "glossary": {
+ "GlossDiv": {
+ "GlossList": [
+ {
+ "Abbrev": "ISO 8879:1986",
+ "Acronym": "SGML",
+ "AvogadroNumber": 6.02e23,
+ "EmptyDict": {},
+ "EmptyList": [],
+ "EvenPrimesGreaterThan2": [],
+ "FermatTheoremInMargin": False,
+ "GlossDef": "A meta-markup language, "
+ "used to create markup "
+ "languages such as "
+ "DocBook.",
+ "GlossSeeAlso": ["GML", "XML", "markup"],
+ "GlossTerm": "Standard Generalized " "Markup Language",
+ "ID": "SGML",
+ "LargestPrimeLessThan100": 97,
+ "MapRequiringFiveColors": None,
+ "PrimesLessThan10": [2, 3, 5, 7],
+ "SortAs": "SGML",
+ }
],
+ "title": "S",
+ },
+ "title": "example glossary",
+ }
+ },
+ {
+ "menu": {
+ "id": "file",
+ "popup": {
+ "menuitem": [
+ {"onclick": "CreateNewDoc()", "value": "New"},
+ {"onclick": "OpenDoc()", "value": "Open"},
+ {"onclick": "CloseDoc()", "value": "Close"},
+ ]
+ },
+ "value": "File:",
+ }
+ },
+ {
+ "widget": {
+ "debug": "on",
+ "image": {
+ "alignment": "center",
+ "hOffset": 250,
+ "name": "sun1",
+ "src": "Images/Sun.png",
+ "vOffset": 250,
+ },
+ "text": {
+ "alignment": "center",
+ "data": "Click Here",
+ "hOffset": 250,
+ "name": "text1",
+ "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;",
+ "size": 36,
+ "style": "bold",
+ "vOffset": 100,
+ },
+ "window": {
+ "height": 500,
+ "name": "main_window",
+ "title": "Sample Konfabulator Widget",
+ "width": 500,
+ },
+ }
+ },
+ {
+ "web-app": {
+ "servlet": [
+ {
+ "init-param": {
+ "cachePackageTagsRefresh": 60,
+ "cachePackageTagsStore": 200,
+ "cachePackageTagsTrack": 200,
+ "cachePagesDirtyRead": 10,
+ "cachePagesRefresh": 10,
+ "cachePagesStore": 100,
+ "cachePagesTrack": 200,
+ "cacheTemplatesRefresh": 15,
+ "cacheTemplatesStore": 50,
+ "cacheTemplatesTrack": 100,
+ "configGlossary:adminEmail": "ksm@pobox.com",
+ "configGlossary:installationAt": "Philadelphia, " "PA",
+ "configGlossary:poweredBy": "Cofax",
+ "configGlossary:poweredByIcon": "/images/cofax.gif",
+ "configGlossary:staticPath": "/content/static",
+ "dataStoreClass": "org.cofax.SqlDataStore",
+ "dataStoreConnUsageLimit": 100,
+ "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+ "dataStoreInitConns": 10,
+ "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+ "dataStoreLogLevel": "debug",
+ "dataStoreMaxConns": 100,
+ "dataStoreName": "cofax",
+ "dataStorePassword": "dataStoreTestQuery",
+ "dataStoreTestQuery": "SET NOCOUNT "
+ "ON;select "
+ "test='test';",
+ "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+ "dataStoreUser": "sa",
+ "defaultFileTemplate": "articleTemplate.htm",
+ "defaultListTemplate": "listTemplate.htm",
+ "jspFileTemplate": "articleTemplate.jsp",
+ "jspListTemplate": "listTemplate.jsp",
+ "maxUrlLength": 500,
+ "redirectionClass": "org.cofax.SqlRedirection",
+ "searchEngineFileTemplate": "forSearchEngines.htm",
+ "searchEngineListTemplate": "forSearchEnginesList.htm",
+ "searchEngineRobotsDb": "WEB-INF/robots.db",
+ "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+ "templateOverridePath": "",
+ "templatePath": "templates",
+ "templateProcessorClass": "org.cofax.WysiwygTemplate",
+ "useDataStore": True,
+ "useJSP": False,
+ },
+ "servlet-class": "org.cofax.cds.CDSServlet",
+ "servlet-name": "cofaxCDS",
+ },
+ {
+ "init-param": {
+ "mailHost": "mail1",
+ "mailHostOverride": "mail2",
+ },
+ "servlet-class": "org.cofax.cds.EmailServlet",
+ "servlet-name": "cofaxEmail",
+ },
+ {
+ "servlet-class": "org.cofax.cds.AdminServlet",
+ "servlet-name": "cofaxAdmin",
+ },
+ {
+ "servlet-class": "org.cofax.cds.FileServlet",
+ "servlet-name": "fileServlet",
+ },
+ {
+ "init-param": {
+ "adminGroupID": 4,
+ "betaServer": True,
+ "dataLog": 1,
+ "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+ "dataLogMaxSize": "",
+ "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+ "log": 1,
+ "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+ "logMaxSize": "",
+ "lookInContext": 1,
+ "removePageCache": "/content/admin/remove?cache=pages&id=",
+ "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+ "templatePath": "toolstemplates/",
+ },
+ "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+ "servlet-name": "cofaxTools",
+ },
],
- ]
- ],
- [
- [
- "menu",
- [
- ["header", "SVG Viewer"],
- [
- "items",
- [
- [["id", "Open"]],
- [["id", "OpenNew"], ["label", "Open New"]],
- None,
- [["id", "ZoomIn"], ["label", "Zoom In"]],
- [["id", "ZoomOut"], ["label", "Zoom Out"]],
- [["id", "OriginalView"], ["label", "Original View"]],
- None,
- [["id", "Quality"]],
- [["id", "Pause"]],
- [["id", "Mute"]],
- None,
- [["id", "Find"], ["label", "Find..."]],
- [["id", "FindAgain"], ["label", "Find Again"]],
- [["id", "Copy"]],
- [["id", "CopyAgain"], ["label", "Copy Again"]],
- [["id", "CopySVG"], ["label", "Copy SVG"]],
- [["id", "ViewSVG"], ["label", "View SVG"]],
- [["id", "ViewSource"], ["label", "View Source"]],
- [["id", "SaveAs"], ["label", "Save As"]],
- None,
- [["id", "Help"]],
- [
- ["id", "About"],
- ["label", "About Adobe CVG Viewer..."],
- ],
- ],
- ],
+ "servlet-mapping": {
+ "cofaxAdmin": "/admin/*",
+ "cofaxCDS": "/",
+ "cofaxEmail": "/cofaxutil/aemail/*",
+ "cofaxTools": "/tools/*",
+ "fileServlet": "/static/*",
+ },
+ "taglib": {
+ "taglib-location": "/WEB-INF/tlds/cofax.tld",
+ "taglib-uri": "cofax.tld",
+ },
+ }
+ },
+ {
+ "menu": {
+ "header": "SVG Viewer",
+ "items": [
+ {"id": "Open"},
+ {"id": "OpenNew", "label": "Open New"},
+ None,
+ {"id": "ZoomIn", "label": "Zoom In"},
+ {"id": "ZoomOut", "label": "Zoom Out"},
+ {"id": "OriginalView", "label": "Original View"},
+ None,
+ {"id": "Quality"},
+ {"id": "Pause"},
+ {"id": "Mute"},
+ None,
+ {"id": "Find", "label": "Find..."},
+ {"id": "FindAgain", "label": "Find Again"},
+ {"id": "Copy"},
+ {"id": "CopyAgain", "label": "Copy Again"},
+ {"id": "CopySVG", "label": "Copy SVG"},
+ {"id": "ViewSVG", "label": "View SVG"},
+ {"id": "ViewSource", "label": "View Source"},
+ {"id": "SaveAs", "label": "Save As"},
+ None,
+ {"id": "Help"},
+ {"id": "About", "label": "About Adobe CVG Viewer..."},
],
- ]
- ],
+ }
+ },
]
- for t, exp in zip((test1, test2, test3, test4, test5), expected):
- self.assertParseAndCheckList(jsonObject, t, exp, verbose=True)
+ for t, exp_result in zip((test1, test2, test3, test4, test5), expected):
+ result = jsonObject.parseString(t)
+ self.assertEqual(exp_result, result[0])
def testParseCommaSeparatedValues(self):
testData = [
@@ -7707,7 +7574,7 @@ class Test2_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
print(res.asDict())
self.assertEqual(
- "(['test', 'blub'], {'word': 'blub'})",
+ "ParseResults(['test', 'blub'], {'word': 'blub'})",
repr(res),
"incorrect repr for ParseResults with listAllMatches=False",
)
@@ -7720,7 +7587,7 @@ class Test2_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
print(res.asDict())
self.assertEqual(
- "(['test', 'blub'], {'word': ['test', 'blub']})",
+ "ParseResults(['test', 'blub'], {'word': ['test', 'blub']})",
repr(res),
"incorrect repr for ParseResults with listAllMatches=True",
)