Imported Upstream version 36.0.0 upstream/36.0.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:32:43 +0000 (10:32 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:32:43 +0000 (10:32 +0900)
70 files changed:
.gitignore
.travis.yml
CHANGES.rst
bootstrap.py
pavement.py [new file with mode: 0644]
pkg_resources/__init__.py
pkg_resources/_vendor/__init__.py [new file with mode: 0644]
pkg_resources/_vendor/appdirs.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/__about__.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/__init__.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/_compat.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/_structures.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/markers.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/requirements.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/specifiers.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/utils.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/version.py [new file with mode: 0644]
pkg_resources/_vendor/pyparsing.py [new file with mode: 0644]
pkg_resources/_vendor/six.py [new file with mode: 0644]
pkg_resources/_vendor/vendored.txt [new file with mode: 0644]
pkg_resources/extern/__init__.py [new file with mode: 0644]
pkg_resources/tests/test_pkg_resources.py
pkg_resources/tests/test_resources.py
pyproject.toml [deleted file]
setup.cfg
setup.py
setuptools/__init__.py
setuptools/command/alias.py
setuptools/command/bdist_egg.py
setuptools/command/build_ext.py
setuptools/command/build_py.py
setuptools/command/develop.py
setuptools/command/easy_install.py
setuptools/command/egg_info.py
setuptools/command/py36compat.py
setuptools/command/rotate.py
setuptools/command/sdist.py
setuptools/command/setopt.py
setuptools/command/test.py
setuptools/command/upload_docs.py
setuptools/config.py
setuptools/dist.py
setuptools/extension.py
setuptools/extern/__init__.py [new file with mode: 0644]
setuptools/glob.py
setuptools/monkey.py
setuptools/msvc.py
setuptools/namespaces.py
setuptools/package_index.py
setuptools/py33compat.py
setuptools/sandbox.py
setuptools/ssl_support.py
setuptools/tests/__init__.py
setuptools/tests/contexts.py
setuptools/tests/server.py
setuptools/tests/test_archive_util.py
setuptools/tests/test_build_ext.py
setuptools/tests/test_develop.py
setuptools/tests/test_dist_info.py
setuptools/tests/test_easy_install.py
setuptools/tests/test_egg_info.py
setuptools/tests/test_integration.py
setuptools/tests/test_manifest.py
setuptools/tests/test_packageindex.py
setuptools/tests/test_sandbox.py
setuptools/tests/test_sdist.py
setuptools/unicode_utils.py
tests/requirements.txt
tests/test_pypi.py
tox.ini

index ec3d0e3..b23ade0 100644 (file)
@@ -13,4 +13,4 @@ setuptools.egg-info
 *.swp
 *~
 .hg*
-requirements.txt
+.cache
index adb2f94..fa26015 100644 (file)
@@ -15,8 +15,8 @@ matrix:
   - python: 2.7
     env: LC_ALL=C LC_CTYPE=C
 script:
- # need tox and rwt to get started
- - pip install tox rwt
+ # need tox to get started
+ - pip install tox
 
  # Output the env, to verify behavior
  - env
@@ -24,6 +24,7 @@ script:
  # update egg_info based on setup.py in checkout
  - python bootstrap.py
 
+ #- python -m tox
  - tox
 
 before_deploy:
index 1ac719d..bc13fd8 100644 (file)
@@ -1,3 +1,14 @@
+v36.0.0
+-------
+
+* #980 and others: Once again, Setuptools vendors all
+  of its dependencies. It seems to be the case that in
+  the Python ecosystem, all build tools must run without
+  any dependencies (build, runtime, or otherwise). At
+  such a point that a mechanism exists that allows
+  build tools to have dependencies, Setuptools will adopt
+  it.
+
 v35.0.2
 -------
 
index ee3b53c..24d7093 100644 (file)
@@ -5,14 +5,7 @@ environment by creating a minimal egg-info directory and then invoking the
 egg-info command to flesh out the egg-info directory.
 """
 
-from __future__ import unicode_literals
-
 import os
-import io
-import re
-import contextlib
-import tempfile
-import shutil
 import sys
 import textwrap
 import subprocess
@@ -48,8 +41,7 @@ def build_egg_info():
     """
 
     os.mkdir('setuptools.egg-info')
-    filename = 'setuptools.egg-info/entry_points.txt'
-    with io.open(filename, 'w', encoding='utf-8') as ep:
+    with open('setuptools.egg-info/entry_points.txt', 'w') as ep:
         ep.write(minimal_egg_info)
 
 
@@ -61,44 +53,9 @@ def run_egg_info():
     subprocess.check_call(cmd)
 
 
-def gen_deps():
-    with io.open('setup.py', encoding='utf-8') as strm:
-        text = strm.read()
-    pattern = r'install_requires=\[(.*?)\]'
-    match = re.search(pattern, text, flags=re.M|re.DOTALL)
-    reqs = eval(match.group(1).replace('\n', ''))
-    with io.open('requirements.txt', 'w', encoding='utf-8') as reqs_file:
-        reqs_file.write('\n'.join(reqs))
-
-
-@contextlib.contextmanager
-def install_deps():
-    "Just in time make the deps available"
-    import pip
-    tmpdir = tempfile.mkdtemp()
-    args = [
-        'install',
-        '-t', tmpdir,
-        '-r', 'requirements.txt',
-    ]
-    pip.main(args)
-    os.environ['PYTHONPATH'] = tmpdir
-    try:
-        yield tmpdir
-    finally:
-        shutil.rmtree(tmpdir)
-
-
 def main():
     ensure_egg_info()
-    gen_deps()
-    try:
-        # first assume dependencies are present
-        run_egg_info()
-    except Exception:
-        # but if that fails, try again with dependencies just in time
-        with install_deps():
-            run_egg_info()
+    run_egg_info()
 
 
 __name__ == '__main__' and main()
diff --git a/pavement.py b/pavement.py
new file mode 100644 (file)
index 0000000..f85617d
--- /dev/null
@@ -0,0 +1,32 @@
+import re
+
+from paver.easy import task, path as Path
+import pip
+
+
+def remove_all(paths):
+    for path in paths:
+        path.rmtree() if path.isdir() else path.remove()
+
+
+@task
+def update_vendored():
+    vendor = Path('pkg_resources/_vendor')
+    # pip uninstall doesn't support -t, so do it manually
+    remove_all(vendor.glob('packaging*'))
+    remove_all(vendor.glob('six*'))
+    remove_all(vendor.glob('pyparsing*'))
+    remove_all(vendor.glob('appdirs*'))
+    install_args = [
+        'install',
+        '-r', str(vendor / 'vendored.txt'),
+        '-t', str(vendor),
+    ]
+    pip.main(install_args)
+    packaging = vendor / 'packaging'
+    for file in packaging.glob('*.py'):
+        text = file.text()
+        text = re.sub(r' (pyparsing|six)', r' pkg_resources.extern.\1', text)
+        file.write_text(text)
+    remove_all(vendor.glob('*.dist-info'))
+    remove_all(vendor.glob('*.egg-info'))
index 220a7cc..2ed07c3 100644 (file)
@@ -45,8 +45,8 @@ except ImportError:
     # Python 3.2 compatibility
     import imp as _imp
 
-import six
-from six.moves import urllib, map, filter
+from pkg_resources.extern import six
+from pkg_resources.extern.six.moves import urllib, map, filter
 
 # capture these to bypass sandboxing
 from os import utime
@@ -67,11 +67,12 @@ try:
 except ImportError:
     importlib_machinery = None
 
-import packaging.version
-import packaging.specifiers
-import packaging.requirements
-import packaging.markers
-import appdirs
+from pkg_resources.extern import appdirs
+from pkg_resources.extern import packaging
+__import__('pkg_resources.extern.packaging.version')
+__import__('pkg_resources.extern.packaging.specifiers')
+__import__('pkg_resources.extern.packaging.requirements')
+__import__('pkg_resources.extern.packaging.markers')
 
 if (3, 0) < sys.version_info < (3, 3):
     raise RuntimeError("Python 3.3 or later is required")
diff --git a/pkg_resources/_vendor/__init__.py b/pkg_resources/_vendor/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pkg_resources/_vendor/appdirs.py b/pkg_resources/_vendor/appdirs.py
new file mode 100644 (file)
index 0000000..f4dba09
--- /dev/null
@@ -0,0 +1,552 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2005-2010 ActiveState Software Inc.
+# Copyright (c) 2013 Eddy PetriÈ™or
+
+"""Utilities for determining application-specific dirs.
+
+See <http://github.com/ActiveState/appdirs> for details and usage.
+"""
+# Dev Notes:
+# - MSDN on where to store app data files:
+#   http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
+# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
+# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+__version_info__ = (1, 4, 0)
+__version__ = '.'.join(map(str, __version_info__))
+
+
+import sys
+import os
+
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    unicode = str
+
+if sys.platform.startswith('java'):
+    import platform
+    os_name = platform.java_ver()[3][0]
+    if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
+        system = 'win32'
+    elif os_name.startswith('Mac'): # "Mac OS X", etc.
+        system = 'darwin'
+    else: # "Linux", "SunOS", "FreeBSD", etc.
+        # Setting this to "linux2" is not ideal, but only Windows or Mac
+        # are actually checked for and the rest of the module expects
+        # *sys.platform* style strings.
+        system = 'linux2'
+else:
+    system = sys.platform
+
+
+
+def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
+    r"""Return full path to the user-specific data dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "roaming" (boolean, default False) can be set True to use the Windows
+            roaming appdata directory. That means that for users on a Windows
+            network setup for roaming profiles, this user data will be
+            sync'd on login. See
+            <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
+            for a discussion of issues.
+
+    Typical user data directories are:
+        Mac OS X:               ~/Library/Application Support/<AppName>
+        Unix:                   ~/.local/share/<AppName>    # or in $XDG_DATA_HOME, if defined
+        Win XP (not roaming):   C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
+        Win XP (roaming):       C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
+        Win 7  (not roaming):   C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
+        Win 7  (roaming):       C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
+
+    For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
+    That means, by default "~/.local/share/<AppName>".
+    """
+    if system == "win32":
+        if appauthor is None:
+            appauthor = appname
+        const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
+        path = os.path.normpath(_get_win_folder(const))
+        if appname:
+            if appauthor is not False:
+                path = os.path.join(path, appauthor, appname)
+            else:
+                path = os.path.join(path, appname)
+    elif system == 'darwin':
+        path = os.path.expanduser('~/Library/Application Support/')
+        if appname:
+            path = os.path.join(path, appname)
+    else:
+        path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
+        if appname:
+            path = os.path.join(path, appname)
+    if appname and version:
+        path = os.path.join(path, version)
+    return path
+
+
+def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
+    """Return full path to the user-shared data dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "multipath" is an optional parameter only applicable to *nix
+            which indicates that the entire list of data dirs should be
+            returned. By default, the first item from XDG_DATA_DIRS is
+            returned, or '/usr/local/share/<AppName>',
+            if XDG_DATA_DIRS is not set
+
+    Typical user data directories are:
+        Mac OS X:   /Library/Application Support/<AppName>
+        Unix:       /usr/local/share/<AppName> or /usr/share/<AppName>
+        Win XP:     C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
+        Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+        Win 7:      C:\ProgramData\<AppAuthor>\<AppName>   # Hidden, but writeable on Win 7.
+
+    For Unix, this is using the $XDG_DATA_DIRS[0] default.
+
+    WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+    """
+    if system == "win32":
+        if appauthor is None:
+            appauthor = appname
+        path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
+        if appname:
+            if appauthor is not False:
+                path = os.path.join(path, appauthor, appname)
+            else:
+                path = os.path.join(path, appname)
+    elif system == 'darwin':
+        path = os.path.expanduser('/Library/Application Support')
+        if appname:
+            path = os.path.join(path, appname)
+    else:
+        # XDG default for $XDG_DATA_DIRS
+        # only first, if multipath is False
+        path = os.getenv('XDG_DATA_DIRS',
+                         os.pathsep.join(['/usr/local/share', '/usr/share']))
+        pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+        if appname:
+            if version:
+                appname = os.path.join(appname, version)
+            pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+        if multipath:
+            path = os.pathsep.join(pathlist)
+        else:
+            path = pathlist[0]
+        return path
+
+    if appname and version:
+        path = os.path.join(path, version)
+    return path
+
+
+def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
+    r"""Return full path to the user-specific config dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "roaming" (boolean, default False) can be set True to use the Windows
+            roaming appdata directory. That means that for users on a Windows
+            network setup for roaming profiles, this user data will be
+            sync'd on login. See
+            <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
+            for a discussion of issues.
+
+    Typical user data directories are:
+        Mac OS X:               same as user_data_dir
+        Unix:                   ~/.config/<AppName>     # or in $XDG_CONFIG_HOME, if defined
+        Win *:                  same as user_data_dir
+
+    For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
+    That means, by deafult "~/.config/<AppName>".
+    """
+    if system in ["win32", "darwin"]:
+        path = user_data_dir(appname, appauthor, None, roaming)
+    else:
+        path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
+        if appname:
+            path = os.path.join(path, appname)
+    if appname and version:
+        path = os.path.join(path, version)
+    return path
+
+
+def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
+    """Return full path to the user-shared data dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "multipath" is an optional parameter only applicable to *nix
+            which indicates that the entire list of config dirs should be
+            returned. By default, the first item from XDG_CONFIG_DIRS is
+            returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
+
+    Typical user data directories are:
+        Mac OS X:   same as site_data_dir
+        Unix:       /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
+                    $XDG_CONFIG_DIRS
+        Win *:      same as site_data_dir
+        Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+
+    For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
+
+    WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+    """
+    if system in ["win32", "darwin"]:
+        path = site_data_dir(appname, appauthor)
+        if appname and version:
+            path = os.path.join(path, version)
+    else:
+        # XDG default for $XDG_CONFIG_DIRS
+        # only first, if multipath is False
+        path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
+        pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+        if appname:
+            if version:
+                appname = os.path.join(appname, version)
+            pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+        if multipath:
+            path = os.pathsep.join(pathlist)
+        else:
+            path = pathlist[0]
+    return path
+
+
+def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
+    r"""Return full path to the user-specific cache dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "opinion" (boolean) can be False to disable the appending of
+            "Cache" to the base app data dir for Windows. See
+            discussion below.
+
+    Typical user cache directories are:
+        Mac OS X:   ~/Library/Caches/<AppName>
+        Unix:       ~/.cache/<AppName> (XDG default)
+        Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
+        Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
+
+    On Windows the only suggestion in the MSDN docs is that local settings go in
+    the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
+    app data dir (the default returned by `user_data_dir` above). Apps typically
+    put cache data somewhere *under* the given dir here. Some examples:
+        ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
+        ...\Acme\SuperApp\Cache\1.0
+    OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
+    This can be disabled with the `opinion=False` option.
+    """
+    if system == "win32":
+        if appauthor is None:
+            appauthor = appname
+        path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
+        if appname:
+            if appauthor is not False:
+                path = os.path.join(path, appauthor, appname)
+            else:
+                path = os.path.join(path, appname)
+            if opinion:
+                path = os.path.join(path, "Cache")
+    elif system == 'darwin':
+        path = os.path.expanduser('~/Library/Caches')
+        if appname:
+            path = os.path.join(path, appname)
+    else:
+        path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
+        if appname:
+            path = os.path.join(path, appname)
+    if appname and version:
+        path = os.path.join(path, version)
+    return path
+
+
+def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
+    r"""Return full path to the user-specific log dir for this application.
+
+        "appname" is the name of application.
+            If None, just the system directory is returned.
+        "appauthor" (only used on Windows) is the name of the
+            appauthor or distributing body for this application. Typically
+            it is the owning company name. This falls back to appname. You may
+            pass False to disable it.
+        "version" is an optional version path element to append to the
+            path. You might want to use this if you want multiple versions
+            of your app to be able to run independently. If used, this
+            would typically be "<major>.<minor>".
+            Only applied when appname is present.
+        "opinion" (boolean) can be False to disable the appending of
+            "Logs" to the base app data dir for Windows, and "log" to the
+            base cache dir for Unix. See discussion below.
+
+    Typical user cache directories are:
+        Mac OS X:   ~/Library/Logs/<AppName>
+        Unix:       ~/.cache/<AppName>/log  # or under $XDG_CACHE_HOME if defined
+        Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
+        Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
+
+    On Windows the only suggestion in the MSDN docs is that local settings
+    go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
+    examples of what some windows apps use for a logs dir.)
+
+    OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
+    value for Windows and appends "log" to the user cache dir for Unix.
+    This can be disabled with the `opinion=False` option.
+    """
+    if system == "darwin":
+        path = os.path.join(
+            os.path.expanduser('~/Library/Logs'),
+            appname)
+    elif system == "win32":
+        path = user_data_dir(appname, appauthor, version)
+        version = False
+        if opinion:
+            path = os.path.join(path, "Logs")
+    else:
+        path = user_cache_dir(appname, appauthor, version)
+        version = False
+        if opinion:
+            path = os.path.join(path, "log")
+    if appname and version:
+        path = os.path.join(path, version)
+    return path
+
+
+class AppDirs(object):
+    """Convenience wrapper for getting application dirs."""
+    def __init__(self, appname, appauthor=None, version=None, roaming=False,
+                 multipath=False):
+        self.appname = appname
+        self.appauthor = appauthor
+        self.version = version
+        self.roaming = roaming
+        self.multipath = multipath
+
+    @property
+    def user_data_dir(self):
+        return user_data_dir(self.appname, self.appauthor,
+                             version=self.version, roaming=self.roaming)
+
+    @property
+    def site_data_dir(self):
+        return site_data_dir(self.appname, self.appauthor,
+                             version=self.version, multipath=self.multipath)
+
+    @property
+    def user_config_dir(self):
+        return user_config_dir(self.appname, self.appauthor,
+                               version=self.version, roaming=self.roaming)
+
+    @property
+    def site_config_dir(self):
+        return site_config_dir(self.appname, self.appauthor,
+                             version=self.version, multipath=self.multipath)
+
+    @property
+    def user_cache_dir(self):
+        return user_cache_dir(self.appname, self.appauthor,
+                              version=self.version)
+
+    @property
+    def user_log_dir(self):
+        return user_log_dir(self.appname, self.appauthor,
+                            version=self.version)
+
+
+#---- internal support stuff
+
+def _get_win_folder_from_registry(csidl_name):
+    """This is a fallback technique at best. I'm not sure if using the
+    registry for this guarantees us the correct answer for all CSIDL_*
+    names.
+    """
+    import _winreg
+
+    shell_folder_name = {
+        "CSIDL_APPDATA": "AppData",
+        "CSIDL_COMMON_APPDATA": "Common AppData",
+        "CSIDL_LOCAL_APPDATA": "Local AppData",
+    }[csidl_name]
+
+    key = _winreg.OpenKey(
+        _winreg.HKEY_CURRENT_USER,
+        r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
+    )
+    dir, type = _winreg.QueryValueEx(key, shell_folder_name)
+    return dir
+
+
+def _get_win_folder_with_pywin32(csidl_name):
+    from win32com.shell import shellcon, shell
+    dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
+    # Try to make this a unicode path because SHGetFolderPath does
+    # not return unicode strings when there is unicode data in the
+    # path.
+    try:
+        dir = unicode(dir)
+
+        # Downgrade to short path name if have highbit chars. See
+        # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+        has_high_char = False
+        for c in dir:
+            if ord(c) > 255:
+                has_high_char = True
+                break
+        if has_high_char:
+            try:
+                import win32api
+                dir = win32api.GetShortPathName(dir)
+            except ImportError:
+                pass
+    except UnicodeError:
+        pass
+    return dir
+
+
+def _get_win_folder_with_ctypes(csidl_name):
+    import ctypes
+
+    csidl_const = {
+        "CSIDL_APPDATA": 26,
+        "CSIDL_COMMON_APPDATA": 35,
+        "CSIDL_LOCAL_APPDATA": 28,
+    }[csidl_name]
+
+    buf = ctypes.create_unicode_buffer(1024)
+    ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
+
+    # Downgrade to short path name if have highbit chars. See
+    # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+    has_high_char = False
+    for c in buf:
+        if ord(c) > 255:
+            has_high_char = True
+            break
+    if has_high_char:
+        buf2 = ctypes.create_unicode_buffer(1024)
+        if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
+            buf = buf2
+
+    return buf.value
+
+def _get_win_folder_with_jna(csidl_name):
+    import array
+    from com.sun import jna
+    from com.sun.jna.platform import win32
+
+    buf_size = win32.WinDef.MAX_PATH * 2
+    buf = array.zeros('c', buf_size)
+    shell = win32.Shell32.INSTANCE
+    shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
+    dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+    # Downgrade to short path name if have highbit chars. See
+    # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+    has_high_char = False
+    for c in dir:
+        if ord(c) > 255:
+            has_high_char = True
+            break
+    if has_high_char:
+        buf = array.zeros('c', buf_size)
+        kernel = win32.Kernel32.INSTANCE
+        if kernal.GetShortPathName(dir, buf, buf_size):
+            dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+    return dir
+
+if system == "win32":
+    try:
+        import win32com.shell
+        _get_win_folder = _get_win_folder_with_pywin32
+    except ImportError:
+        try:
+            from ctypes import windll
+            _get_win_folder = _get_win_folder_with_ctypes
+        except ImportError:
+            try:
+                import com.sun.jna
+                _get_win_folder = _get_win_folder_with_jna
+            except ImportError:
+                _get_win_folder = _get_win_folder_from_registry
+
+
+#---- self test code
+
+if __name__ == "__main__":
+    appname = "MyApp"
+    appauthor = "MyCompany"
+
+    props = ("user_data_dir", "site_data_dir",
+             "user_config_dir", "site_config_dir",
+             "user_cache_dir", "user_log_dir")
+
+    print("-- app dirs (with optional 'version')")
+    dirs = AppDirs(appname, appauthor, version="1.0")
+    for prop in props:
+        print("%s: %s" % (prop, getattr(dirs, prop)))
+
+    print("\n-- app dirs (without optional 'version')")
+    dirs = AppDirs(appname, appauthor)
+    for prop in props:
+        print("%s: %s" % (prop, getattr(dirs, prop)))
+
+    print("\n-- app dirs (without optional 'appauthor')")
+    dirs = AppDirs(appname)
+    for prop in props:
+        print("%s: %s" % (prop, getattr(dirs, prop)))
+
+    print("\n-- app dirs (with disabled 'appauthor')")
+    dirs = AppDirs(appname, appauthor=False)
+    for prop in props:
+        print("%s: %s" % (prop, getattr(dirs, prop)))
diff --git a/pkg_resources/_vendor/packaging/__about__.py b/pkg_resources/_vendor/packaging/__about__.py
new file mode 100644 (file)
index 0000000..95d330e
--- /dev/null
@@ -0,0 +1,21 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+__all__ = [
+    "__title__", "__summary__", "__uri__", "__version__", "__author__",
+    "__email__", "__license__", "__copyright__",
+]
+
+__title__ = "packaging"
+__summary__ = "Core utilities for Python packages"
+__uri__ = "https://github.com/pypa/packaging"
+
+__version__ = "16.8"
+
+__author__ = "Donald Stufft and individual contributors"
+__email__ = "donald@stufft.io"
+
+__license__ = "BSD or Apache License, Version 2.0"
+__copyright__ = "Copyright 2014-2016 %s" % __author__
diff --git a/pkg_resources/_vendor/packaging/__init__.py b/pkg_resources/_vendor/packaging/__init__.py
new file mode 100644 (file)
index 0000000..5ee6220
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+from .__about__ import (
+    __author__, __copyright__, __email__, __license__, __summary__, __title__,
+    __uri__, __version__
+)
+
+__all__ = [
+    "__title__", "__summary__", "__uri__", "__version__", "__author__",
+    "__email__", "__license__", "__copyright__",
+]
diff --git a/pkg_resources/_vendor/packaging/_compat.py b/pkg_resources/_vendor/packaging/_compat.py
new file mode 100644 (file)
index 0000000..210bb80
--- /dev/null
@@ -0,0 +1,30 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import sys
+
+
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+
+# flake8: noqa
+
+if PY3:
+    string_types = str,
+else:
+    string_types = basestring,
+
+
+def with_metaclass(meta, *bases):
+    """
+    Create a base class with a metaclass.
+    """
+    # This requires a bit of explanation: the basic idea is to make a dummy
+    # metaclass for one level of class instantiation that replaces itself with
+    # the actual metaclass.
+    class metaclass(meta):
+        def __new__(cls, name, this_bases, d):
+            return meta(name, bases, d)
+    return type.__new__(metaclass, 'temporary_class', (), {})
diff --git a/pkg_resources/_vendor/packaging/_structures.py b/pkg_resources/_vendor/packaging/_structures.py
new file mode 100644 (file)
index 0000000..ccc2786
--- /dev/null
@@ -0,0 +1,68 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+
+class Infinity(object):
+
+    def __repr__(self):
+        return "Infinity"
+
+    def __hash__(self):
+        return hash(repr(self))
+
+    def __lt__(self, other):
+        return False
+
+    def __le__(self, other):
+        return False
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__)
+
+    def __ne__(self, other):
+        return not isinstance(other, self.__class__)
+
+    def __gt__(self, other):
+        return True
+
+    def __ge__(self, other):
+        return True
+
+    def __neg__(self):
+        return NegativeInfinity
+
+Infinity = Infinity()
+
+
+class NegativeInfinity(object):
+
+    def __repr__(self):
+        return "-Infinity"
+
+    def __hash__(self):
+        return hash(repr(self))
+
+    def __lt__(self, other):
+        return True
+
+    def __le__(self, other):
+        return True
+
+    def __eq__(self, other):
+        return isinstance(other, self.__class__)
+
+    def __ne__(self, other):
+        return not isinstance(other, self.__class__)
+
+    def __gt__(self, other):
+        return False
+
+    def __ge__(self, other):
+        return False
+
+    def __neg__(self):
+        return Infinity
+
+NegativeInfinity = NegativeInfinity()
diff --git a/pkg_resources/_vendor/packaging/markers.py b/pkg_resources/_vendor/packaging/markers.py
new file mode 100644 (file)
index 0000000..892e578
--- /dev/null
@@ -0,0 +1,301 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import operator
+import os
+import platform
+import sys
+
+from pkg_resources.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd
+from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
+from pkg_resources.extern.pyparsing import Literal as L  # noqa
+
+from ._compat import string_types
+from .specifiers import Specifier, InvalidSpecifier
+
+
+__all__ = [
+    "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
+    "Marker", "default_environment",
+]
+
+
+class InvalidMarker(ValueError):
+    """
+    An invalid marker was found, users should refer to PEP 508.
+    """
+
+
+class UndefinedComparison(ValueError):
+    """
+    An invalid operation was attempted on a value that doesn't support it.
+    """
+
+
+class UndefinedEnvironmentName(ValueError):
+    """
+    A name was attempted to be used that does not exist inside of the
+    environment.
+    """
+
+
+class Node(object):
+
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return str(self.value)
+
+    def __repr__(self):
+        return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
+
+    def serialize(self):
+        raise NotImplementedError
+
+
+class Variable(Node):
+
+    def serialize(self):
+        return str(self)
+
+
+class Value(Node):
+
+    def serialize(self):
+        return '"{0}"'.format(self)
+
+
+class Op(Node):
+
+    def serialize(self):
+        return str(self)
+
+
+VARIABLE = (
+    L("implementation_version") |
+    L("platform_python_implementation") |
+    L("implementation_name") |
+    L("python_full_version") |
+    L("platform_release") |
+    L("platform_version") |
+    L("platform_machine") |
+    L("platform_system") |
+    L("python_version") |
+    L("sys_platform") |
+    L("os_name") |
+    L("os.name") |  # PEP-345
+    L("sys.platform") |  # PEP-345
+    L("platform.version") |  # PEP-345
+    L("platform.machine") |  # PEP-345
+    L("platform.python_implementation") |  # PEP-345
+    L("python_implementation") |  # undocumented setuptools legacy
+    L("extra")
+)
+ALIASES = {
+    'os.name': 'os_name',
+    'sys.platform': 'sys_platform',
+    'platform.version': 'platform_version',
+    'platform.machine': 'platform_machine',
+    'platform.python_implementation': 'platform_python_implementation',
+    'python_implementation': 'platform_python_implementation'
+}
+VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
+
+VERSION_CMP = (
+    L("===") |
+    L("==") |
+    L(">=") |
+    L("<=") |
+    L("!=") |
+    L("~=") |
+    L(">") |
+    L("<")
+)
+
+MARKER_OP = VERSION_CMP | L("not in") | L("in")
+MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
+
+MARKER_VALUE = QuotedString("'") | QuotedString('"')
+MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
+
+BOOLOP = L("and") | L("or")
+
+MARKER_VAR = VARIABLE | MARKER_VALUE
+
+MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
+MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
+
+LPAREN = L("(").suppress()
+RPAREN = L(")").suppress()
+
+MARKER_EXPR = Forward()
+MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
+MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR)
+
+MARKER = stringStart + MARKER_EXPR + stringEnd
+
+
+def _coerce_parse_result(results):
+    if isinstance(results, ParseResults):
+        return [_coerce_parse_result(i) for i in results]
+    else:
+        return results
+
+
+def _format_marker(marker, first=True):
+    assert isinstance(marker, (list, tuple, string_types))
+
+    # Sometimes we have a structure like [[...]] which is a single item list
+    # where the single item is itself it's own list. In that case we want skip
+    # the rest of this function so that we don't get extraneous () on the
+    # outside.
+    if (isinstance(marker, list) and len(marker) == 1 and
+            isinstance(marker[0], (list, tuple))):
+        return _format_marker(marker[0])
+
+    if isinstance(marker, list):
+        inner = (_format_marker(m, first=False) for m in marker)
+        if first:
+            return " ".join(inner)
+        else:
+            return "(" + " ".join(inner) + ")"
+    elif isinstance(marker, tuple):
+        return " ".join([m.serialize() for m in marker])
+    else:
+        return marker
+
+
+_operators = {
+    "in": lambda lhs, rhs: lhs in rhs,
+    "not in": lambda lhs, rhs: lhs not in rhs,
+    "<": operator.lt,
+    "<=": operator.le,
+    "==": operator.eq,
+    "!=": operator.ne,
+    ">=": operator.ge,
+    ">": operator.gt,
+}
+
+
+def _eval_op(lhs, op, rhs):
+    try:
+        spec = Specifier("".join([op.serialize(), rhs]))
+    except InvalidSpecifier:
+        pass
+    else:
+        return spec.contains(lhs)
+
+    oper = _operators.get(op.serialize())
+    if oper is None:
+        raise UndefinedComparison(
+            "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
+        )
+
+    return oper(lhs, rhs)
+
+
+_undefined = object()
+
+
+def _get_env(environment, name):
+    value = environment.get(name, _undefined)
+
+    if value is _undefined:
+        raise UndefinedEnvironmentName(
+            "{0!r} does not exist in evaluation environment.".format(name)
+        )
+
+    return value
+
+
+def _evaluate_markers(markers, environment):
+    groups = [[]]
+
+    for marker in markers:
+        assert isinstance(marker, (list, tuple, string_types))
+
+        if isinstance(marker, list):
+            groups[-1].append(_evaluate_markers(marker, environment))
+        elif isinstance(marker, tuple):
+            lhs, op, rhs = marker
+
+            if isinstance(lhs, Variable):
+                lhs_value = _get_env(environment, lhs.value)
+                rhs_value = rhs.value
+            else:
+                lhs_value = lhs.value
+                rhs_value = _get_env(environment, rhs.value)
+
+            groups[-1].append(_eval_op(lhs_value, op, rhs_value))
+        else:
+            assert marker in ["and", "or"]
+            if marker == "or":
+                groups.append([])
+
+    return any(all(item) for item in groups)
+
+
+def format_full_version(info):
+    version = '{0.major}.{0.minor}.{0.micro}'.format(info)
+    kind = info.releaselevel
+    if kind != 'final':
+        version += kind[0] + str(info.serial)
+    return version
+
+
+def default_environment():
+    if hasattr(sys, 'implementation'):
+        iver = format_full_version(sys.implementation.version)
+        implementation_name = sys.implementation.name
+    else:
+        iver = '0'
+        implementation_name = ''
+
+    return {
+        "implementation_name": implementation_name,
+        "implementation_version": iver,
+        "os_name": os.name,
+        "platform_machine": platform.machine(),
+        "platform_release": platform.release(),
+        "platform_system": platform.system(),
+        "platform_version": platform.version(),
+        "python_full_version": platform.python_version(),
+        "platform_python_implementation": platform.python_implementation(),
+        "python_version": platform.python_version()[:3],
+        "sys_platform": sys.platform,
+    }
+
+
+class Marker(object):
+
+    def __init__(self, marker):
+        try:
+            self._markers = _coerce_parse_result(MARKER.parseString(marker))
+        except ParseException as e:
+            err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
+                marker, marker[e.loc:e.loc + 8])
+            raise InvalidMarker(err_str)
+
+    def __str__(self):
+        return _format_marker(self._markers)
+
+    def __repr__(self):
+        return "<Marker({0!r})>".format(str(self))
+
+    def evaluate(self, environment=None):
+        """Evaluate a marker.
+
+        Return the boolean from evaluating the given marker against the
+        environment. environment is an optional argument to override all or
+        part of the determined environment.
+
+        The environment is determined from the current Python process.
+        """
+        current_environment = default_environment()
+        if environment is not None:
+            current_environment.update(environment)
+
+        return _evaluate_markers(self._markers, current_environment)
diff --git a/pkg_resources/_vendor/packaging/requirements.py b/pkg_resources/_vendor/packaging/requirements.py
new file mode 100644 (file)
index 0000000..0c8c4a3
--- /dev/null
@@ -0,0 +1,127 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import string
+import re
+
+from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
+from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
+from pkg_resources.extern.pyparsing import Literal as L  # noqa
+from pkg_resources.extern.six.moves.urllib import parse as urlparse
+
+from .markers import MARKER_EXPR, Marker
+from .specifiers import LegacySpecifier, Specifier, SpecifierSet
+
+
+class InvalidRequirement(ValueError):
+    """
+    An invalid requirement was found, users should refer to PEP 508.
+    """
+
+
+ALPHANUM = Word(string.ascii_letters + string.digits)
+
+LBRACKET = L("[").suppress()
+RBRACKET = L("]").suppress()
+LPAREN = L("(").suppress()
+RPAREN = L(")").suppress()
+COMMA = L(",").suppress()
+SEMICOLON = L(";").suppress()
+AT = L("@").suppress()
+
+PUNCTUATION = Word("-_.")
+IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
+IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
+
+NAME = IDENTIFIER("name")
+EXTRA = IDENTIFIER
+
+URI = Regex(r'[^ ]+')("url")
+URL = (AT + URI)
+
+EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
+EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
+
+VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
+VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
+
+VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
+VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
+                       joinString=",", adjacent=False)("_raw_spec")
+_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
+_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
+
+VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
+VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
+
+MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
+MARKER_EXPR.setParseAction(
+    lambda s, l, t: Marker(s[t._original_start:t._original_end])
+)
+MARKER_SEPERATOR = SEMICOLON
+MARKER = MARKER_SEPERATOR + MARKER_EXPR
+
+VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
+URL_AND_MARKER = URL + Optional(MARKER)
+
+NAMED_REQUIREMENT = \
+    NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
+
+REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
+
+
+class Requirement(object):
+    """Parse a requirement.
+
+    Parse a given requirement string into its parts, such as name, specifier,
+    URL, and extras. Raises InvalidRequirement on a badly-formed requirement
+    string.
+    """
+
+    # TODO: Can we test whether something is contained within a requirement?
+    #       If so how do we do that? Do we need to test against the _name_ of
+    #       the thing as well as the version? What about the markers?
+    # TODO: Can we normalize the name and extra name?
+
+    def __init__(self, requirement_string):
+        try:
+            req = REQUIREMENT.parseString(requirement_string)
+        except ParseException as e:
+            raise InvalidRequirement(
+                "Invalid requirement, parse error at \"{0!r}\"".format(
+                    requirement_string[e.loc:e.loc + 8]))
+
+        self.name = req.name
+        if req.url:
+            parsed_url = urlparse.urlparse(req.url)
+            if not (parsed_url.scheme and parsed_url.netloc) or (
+                    not parsed_url.scheme and not parsed_url.netloc):
+                raise InvalidRequirement("Invalid URL given")
+            self.url = req.url
+        else:
+            self.url = None
+        self.extras = set(req.extras.asList() if req.extras else [])
+        self.specifier = SpecifierSet(req.specifier)
+        self.marker = req.marker if req.marker else None
+
+    def __str__(self):
+        parts = [self.name]
+
+        if self.extras:
+            parts.append("[{0}]".format(",".join(sorted(self.extras))))
+
+        if self.specifier:
+            parts.append(str(self.specifier))
+
+        if self.url:
+            parts.append("@ {0}".format(self.url))
+
+        if self.marker:
+            parts.append("; {0}".format(self.marker))
+
+        return "".join(parts)
+
+    def __repr__(self):
+        return "<Requirement({0!r})>".format(str(self))
diff --git a/pkg_resources/_vendor/packaging/specifiers.py b/pkg_resources/_vendor/packaging/specifiers.py
new file mode 100644 (file)
index 0000000..7f5a76c
--- /dev/null
@@ -0,0 +1,774 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import abc
+import functools
+import itertools
+import re
+
+from ._compat import string_types, with_metaclass
+from .version import Version, LegacyVersion, parse
+
+
+class InvalidSpecifier(ValueError):
+    """
+    An invalid specifier was found, users should refer to PEP 440.
+    """
+
+
+class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
+
+    @abc.abstractmethod
+    def __str__(self):
+        """
+        Returns the str representation of this Specifier like object. This
+        should be representative of the Specifier itself.
+        """
+
+    @abc.abstractmethod
+    def __hash__(self):
+        """
+        Returns a hash value for this Specifier like object.
+        """
+
+    @abc.abstractmethod
+    def __eq__(self, other):
+        """
+        Returns a boolean representing whether or not the two Specifier like
+        objects are equal.
+        """
+
+    @abc.abstractmethod
+    def __ne__(self, other):
+        """
+        Returns a boolean representing whether or not the two Specifier like
+        objects are not equal.
+        """
+
+    @abc.abstractproperty
+    def prereleases(self):
+        """
+        Returns whether or not pre-releases as a whole are allowed by this
+        specifier.
+        """
+
+    @prereleases.setter
+    def prereleases(self, value):
+        """
+        Sets whether or not pre-releases as a whole are allowed by this
+        specifier.
+        """
+
+    @abc.abstractmethod
+    def contains(self, item, prereleases=None):
+        """
+        Determines if the given item is contained within this specifier.
+        """
+
+    @abc.abstractmethod
+    def filter(self, iterable, prereleases=None):
+        """
+        Takes an iterable of items and filters them so that only items which
+        are contained within this specifier are allowed in it.
+        """
+
+
+class _IndividualSpecifier(BaseSpecifier):
+
+    _operators = {}
+
+    def __init__(self, spec="", prereleases=None):
+        match = self._regex.search(spec)
+        if not match:
+            raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
+
+        self._spec = (
+            match.group("operator").strip(),
+            match.group("version").strip(),
+        )
+
+        # Store whether or not this Specifier should accept prereleases
+        self._prereleases = prereleases
+
+    def __repr__(self):
+        pre = (
+            ", prereleases={0!r}".format(self.prereleases)
+            if self._prereleases is not None
+            else ""
+        )
+
+        return "<{0}({1!r}{2})>".format(
+            self.__class__.__name__,
+            str(self),
+            pre,
+        )
+
+    def __str__(self):
+        return "{0}{1}".format(*self._spec)
+
+    def __hash__(self):
+        return hash(self._spec)
+
+    def __eq__(self, other):
+        if isinstance(other, string_types):
+            try:
+                other = self.__class__(other)
+            except InvalidSpecifier:
+                return NotImplemented
+        elif not isinstance(other, self.__class__):
+            return NotImplemented
+
+        return self._spec == other._spec
+
+    def __ne__(self, other):
+        if isinstance(other, string_types):
+            try:
+                other = self.__class__(other)
+            except InvalidSpecifier:
+                return NotImplemented
+        elif not isinstance(other, self.__class__):
+            return NotImplemented
+
+        return self._spec != other._spec
+
+    def _get_operator(self, op):
+        return getattr(self, "_compare_{0}".format(self._operators[op]))
+
+    def _coerce_version(self, version):
+        if not isinstance(version, (LegacyVersion, Version)):
+            version = parse(version)
+        return version
+
+    @property
+    def operator(self):
+        return self._spec[0]
+
+    @property
+    def version(self):
+        return self._spec[1]
+
+    @property
+    def prereleases(self):
+        return self._prereleases
+
+    @prereleases.setter
+    def prereleases(self, value):
+        self._prereleases = value
+
+    def __contains__(self, item):
+        return self.contains(item)
+
+    def contains(self, item, prereleases=None):
+        # Determine if prereleases are to be allowed or not.
+        if prereleases is None:
+            prereleases = self.prereleases
+
+        # Normalize item to a Version or LegacyVersion, this allows us to have
+        # a shortcut for ``"2.0" in Specifier(">=2")
+        item = self._coerce_version(item)
+
+        # Determine if we should be supporting prereleases in this specifier
+        # or not, if we do not support prereleases than we can short circuit
+        # logic if this version is a prereleases.
+        if item.is_prerelease and not prereleases:
+            return False
+
+        # Actually do the comparison to determine if this item is contained
+        # within this Specifier or not.
+        return self._get_operator(self.operator)(item, self.version)
+
+    def filter(self, iterable, prereleases=None):
+        yielded = False
+        found_prereleases = []
+
+        kw = {"prereleases": prereleases if prereleases is not None else True}
+
+        # Attempt to iterate over all the values in the iterable and if any of
+        # them match, yield them.
+        for version in iterable:
+            parsed_version = self._coerce_version(version)
+
+            if self.contains(parsed_version, **kw):
+                # If our version is a prerelease, and we were not set to allow
+                # prereleases, then we'll store it for later incase nothing
+                # else matches this specifier.
+                if (parsed_version.is_prerelease and not
+                        (prereleases or self.prereleases)):
+                    found_prereleases.append(version)
+                # Either this is not a prerelease, or we should have been
+                # accepting prereleases from the begining.
+                else:
+                    yielded = True
+                    yield version
+
+        # Now that we've iterated over everything, determine if we've yielded
+        # any values, and if we have not and we have any prereleases stored up
+        # then we will go ahead and yield the prereleases.
+        if not yielded and found_prereleases:
+            for version in found_prereleases:
+                yield version
+
+
+class LegacySpecifier(_IndividualSpecifier):
+
+    _regex_str = (
+        r"""
+        (?P<operator>(==|!=|<=|>=|<|>))
+        \s*
+        (?P<version>
+            [^,;\s)]* # Since this is a "legacy" specifier, and the version
+                      # string can be just about anything, we match everything
+                      # except for whitespace, a semi-colon for marker support,
+                      # a closing paren since versions can be enclosed in
+                      # them, and a comma since it's a version separator.
+        )
+        """
+    )
+
+    _regex = re.compile(
+        r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+
+    _operators = {
+        "==": "equal",
+        "!=": "not_equal",
+        "<=": "less_than_equal",
+        ">=": "greater_than_equal",
+        "<": "less_than",
+        ">": "greater_than",
+    }
+
+    def _coerce_version(self, version):
+        if not isinstance(version, LegacyVersion):
+            version = LegacyVersion(str(version))
+        return version
+
+    def _compare_equal(self, prospective, spec):
+        return prospective == self._coerce_version(spec)
+
+    def _compare_not_equal(self, prospective, spec):
+        return prospective != self._coerce_version(spec)
+
+    def _compare_less_than_equal(self, prospective, spec):
+        return prospective <= self._coerce_version(spec)
+
+    def _compare_greater_than_equal(self, prospective, spec):
+        return prospective >= self._coerce_version(spec)
+
+    def _compare_less_than(self, prospective, spec):
+        return prospective < self._coerce_version(spec)
+
+    def _compare_greater_than(self, prospective, spec):
+        return prospective > self._coerce_version(spec)
+
+
+def _require_version_compare(fn):
+    @functools.wraps(fn)
+    def wrapped(self, prospective, spec):
+        if not isinstance(prospective, Version):
+            return False
+        return fn(self, prospective, spec)
+    return wrapped
+
+
+class Specifier(_IndividualSpecifier):
+
+    _regex_str = (
+        r"""
+        (?P<operator>(~=|==|!=|<=|>=|<|>|===))
+        (?P<version>
+            (?:
+                # The identity operators allow for an escape hatch that will
+                # do an exact string match of the version you wish to install.
+                # This will not be parsed by PEP 440 and we cannot determine
+                # any semantic meaning from it. This operator is discouraged
+                # but included entirely as an escape hatch.
+                (?<====)  # Only match for the identity operator
+                \s*
+                [^\s]*    # We just match everything, except for whitespace
+                          # since we are only testing for strict identity.
+            )
+            |
+            (?:
+                # The (non)equality operators allow for wild card and local
+                # versions to be specified so we have to define these two
+                # operators separately to enable that.
+                (?<===|!=)            # Only match for equals and not equals
+
+                \s*
+                v?
+                (?:[0-9]+!)?          # epoch
+                [0-9]+(?:\.[0-9]+)*   # release
+                (?:                   # pre release
+                    [-_\.]?
+                    (a|b|c|rc|alpha|beta|pre|preview)
+                    [-_\.]?
+                    [0-9]*
+                )?
+                (?:                   # post release
+                    (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
+                )?
+
+                # You cannot use a wild card and a dev or local version
+                # together so group them with a | and make them optional.
+                (?:
+                    (?:[-_\.]?dev[-_\.]?[0-9]*)?         # dev release
+                    (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
+                    |
+                    \.\*  # Wild card syntax of .*
+                )?
+            )
+            |
+            (?:
+                # The compatible operator requires at least two digits in the
+                # release segment.
+                (?<=~=)               # Only match for the compatible operator
+
+                \s*
+                v?
+                (?:[0-9]+!)?          # epoch
+                [0-9]+(?:\.[0-9]+)+   # release  (We have a + instead of a *)
+                (?:                   # pre release
+                    [-_\.]?
+                    (a|b|c|rc|alpha|beta|pre|preview)
+                    [-_\.]?
+                    [0-9]*
+                )?
+                (?:                                   # post release
+                    (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
+                )?
+                (?:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release
+            )
+            |
+            (?:
+                # All other operators only allow a sub set of what the
+                # (non)equality operators do. Specifically they do not allow
+                # local versions to be specified nor do they allow the prefix
+                # matching wild cards.
+                (?<!==|!=|~=)         # We have special cases for these
+                                      # operators so we want to make sure they
+                                      # don't match here.
+
+                \s*
+                v?
+                (?:[0-9]+!)?          # epoch
+                [0-9]+(?:\.[0-9]+)*   # release
+                (?:                   # pre release
+                    [-_\.]?
+                    (a|b|c|rc|alpha|beta|pre|preview)
+                    [-_\.]?
+                    [0-9]*
+                )?
+                (?:                                   # post release
+                    (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
+                )?
+                (?:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release
+            )
+        )
+        """
+    )
+
+    _regex = re.compile(
+        r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+
+    _operators = {
+        "~=": "compatible",
+        "==": "equal",
+        "!=": "not_equal",
+        "<=": "less_than_equal",
+        ">=": "greater_than_equal",
+        "<": "less_than",
+        ">": "greater_than",
+        "===": "arbitrary",
+    }
+
+    @_require_version_compare
+    def _compare_compatible(self, prospective, spec):
+        # Compatible releases have an equivalent combination of >= and ==. That
+        # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
+        # implement this in terms of the other specifiers instead of
+        # implementing it ourselves. The only thing we need to do is construct
+        # the other specifiers.
+
+        # We want everything but the last item in the version, but we want to
+        # ignore post and dev releases and we want to treat the pre-release as
+        # it's own separate segment.
+        prefix = ".".join(
+            list(
+                itertools.takewhile(
+                    lambda x: (not x.startswith("post") and not
+                               x.startswith("dev")),
+                    _version_split(spec),
+                )
+            )[:-1]
+        )
+
+        # Add the prefix notation to the end of our string
+        prefix += ".*"
+
+        return (self._get_operator(">=")(prospective, spec) and
+                self._get_operator("==")(prospective, prefix))
+
+    @_require_version_compare
+    def _compare_equal(self, prospective, spec):
+        # We need special logic to handle prefix matching
+        if spec.endswith(".*"):
+            # In the case of prefix matching we want to ignore local segment.
+            prospective = Version(prospective.public)
+            # Split the spec out by dots, and pretend that there is an implicit
+            # dot in between a release segment and a pre-release segment.
+            spec = _version_split(spec[:-2])  # Remove the trailing .*
+
+            # Split the prospective version out by dots, and pretend that there
+            # is an implicit dot in between a release segment and a pre-release
+            # segment.
+            prospective = _version_split(str(prospective))
+
+            # Shorten the prospective version to be the same length as the spec
+            # so that we can determine if the specifier is a prefix of the
+            # prospective version or not.
+            prospective = prospective[:len(spec)]
+
+            # Pad out our two sides with zeros so that they both equal the same
+            # length.
+            spec, prospective = _pad_version(spec, prospective)
+        else:
+            # Convert our spec string into a Version
+            spec = Version(spec)
+
+            # If the specifier does not have a local segment, then we want to
+            # act as if the prospective version also does not have a local
+            # segment.
+            if not spec.local:
+                prospective = Version(prospective.public)
+
+        return prospective == spec
+
+    @_require_version_compare
+    def _compare_not_equal(self, prospective, spec):
+        return not self._compare_equal(prospective, spec)
+
+    @_require_version_compare
+    def _compare_less_than_equal(self, prospective, spec):
+        return prospective <= Version(spec)
+
+    @_require_version_compare
+    def _compare_greater_than_equal(self, prospective, spec):
+        return prospective >= Version(spec)
+
+    @_require_version_compare
+    def _compare_less_than(self, prospective, spec):
+        # Convert our spec to a Version instance, since we'll want to work with
+        # it as a version.
+        spec = Version(spec)
+
+        # Check to see if the prospective version is less than the spec
+        # version. If it's not we can short circuit and just return False now
+        # instead of doing extra unneeded work.
+        if not prospective < spec:
+            return False
+
+        # This special case is here so that, unless the specifier itself
+        # includes is a pre-release version, that we do not accept pre-release
+        # versions for the version mentioned in the specifier (e.g. <3.1 should
+        # not match 3.1.dev0, but should match 3.0.dev0).
+        if not spec.is_prerelease and prospective.is_prerelease:
+            if Version(prospective.base_version) == Version(spec.base_version):
+                return False
+
+        # If we've gotten to here, it means that prospective version is both
+        # less than the spec version *and* it's not a pre-release of the same
+        # version in the spec.
+        return True
+
+    @_require_version_compare
+    def _compare_greater_than(self, prospective, spec):
+        # Convert our spec to a Version instance, since we'll want to work with
+        # it as a version.
+        spec = Version(spec)
+
+        # Check to see if the prospective version is greater than the spec
+        # version. If it's not we can short circuit and just return False now
+        # instead of doing extra unneeded work.
+        if not prospective > spec:
+            return False
+
+        # This special case is here so that, unless the specifier itself
+        # includes is a post-release version, that we do not accept
+        # post-release versions for the version mentioned in the specifier
+        # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
+        if not spec.is_postrelease and prospective.is_postrelease:
+            if Version(prospective.base_version) == Version(spec.base_version):
+                return False
+
+        # Ensure that we do not allow a local version of the version mentioned
+        # in the specifier, which is techincally greater than, to match.
+        if prospective.local is not None:
+            if Version(prospective.base_version) == Version(spec.base_version):
+                return False
+
+        # If we've gotten to here, it means that prospective version is both
+        # greater than the spec version *and* it's not a pre-release of the
+        # same version in the spec.
+        return True
+
+    def _compare_arbitrary(self, prospective, spec):
+        return str(prospective).lower() == str(spec).lower()
+
+    @property
+    def prereleases(self):
+        # If there is an explicit prereleases set for this, then we'll just
+        # blindly use that.
+        if self._prereleases is not None:
+            return self._prereleases
+
+        # Look at all of our specifiers and determine if they are inclusive
+        # operators, and if they are if they are including an explicit
+        # prerelease.
+        operator, version = self._spec
+        if operator in ["==", ">=", "<=", "~=", "==="]:
+            # The == specifier can include a trailing .*, if it does we
+            # want to remove before parsing.
+            if operator == "==" and version.endswith(".*"):
+                version = version[:-2]
+
+            # Parse the version, and if it is a pre-release than this
+            # specifier allows pre-releases.
+            if parse(version).is_prerelease:
+                return True
+
+        return False
+
+    @prereleases.setter
+    def prereleases(self, value):
+        self._prereleases = value
+
+
+_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
+
+
+def _version_split(version):
+    result = []
+    for item in version.split("."):
+        match = _prefix_regex.search(item)
+        if match:
+            result.extend(match.groups())
+        else:
+            result.append(item)
+    return result
+
+
+def _pad_version(left, right):
+    left_split, right_split = [], []
+
+    # Get the release segment of our versions
+    left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
+    right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
+
+    # Get the rest of our versions
+    left_split.append(left[len(left_split[0]):])
+    right_split.append(right[len(right_split[0]):])
+
+    # Insert our padding
+    left_split.insert(
+        1,
+        ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
+    )
+    right_split.insert(
+        1,
+        ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
+    )
+
+    return (
+        list(itertools.chain(*left_split)),
+        list(itertools.chain(*right_split)),
+    )
+
+
+class SpecifierSet(BaseSpecifier):
+
+    def __init__(self, specifiers="", prereleases=None):
+        # Split on , to break each indidivual specifier into it's own item, and
+        # strip each item to remove leading/trailing whitespace.
+        specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
+
+        # Parsed each individual specifier, attempting first to make it a
+        # Specifier and falling back to a LegacySpecifier.
+        parsed = set()
+        for specifier in specifiers:
+            try:
+                parsed.add(Specifier(specifier))
+            except InvalidSpecifier:
+                parsed.add(LegacySpecifier(specifier))
+
+        # Turn our parsed specifiers into a frozen set and save them for later.
+        self._specs = frozenset(parsed)
+
+        # Store our prereleases value so we can use it later to determine if
+        # we accept prereleases or not.
+        self._prereleases = prereleases
+
+    def __repr__(self):
+        pre = (
+            ", prereleases={0!r}".format(self.prereleases)
+            if self._prereleases is not None
+            else ""
+        )
+
+        return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
+
+    def __str__(self):
+        return ",".join(sorted(str(s) for s in self._specs))
+
+    def __hash__(self):
+        return hash(self._specs)
+
+    def __and__(self, other):
+        if isinstance(other, string_types):
+            other = SpecifierSet(other)
+        elif not isinstance(other, SpecifierSet):
+            return NotImplemented
+
+        specifier = SpecifierSet()
+        specifier._specs = frozenset(self._specs | other._specs)
+
+        if self._prereleases is None and other._prereleases is not None:
+            specifier._prereleases = other._prereleases
+        elif self._prereleases is not None and other._prereleases is None:
+            specifier._prereleases = self._prereleases
+        elif self._prereleases == other._prereleases:
+            specifier._prereleases = self._prereleases
+        else:
+            raise ValueError(
+                "Cannot combine SpecifierSets with True and False prerelease "
+                "overrides."
+            )
+
+        return specifier
+
+    def __eq__(self, other):
+        if isinstance(other, string_types):
+            other = SpecifierSet(other)
+        elif isinstance(other, _IndividualSpecifier):
+            other = SpecifierSet(str(other))
+        elif not isinstance(other, SpecifierSet):
+            return NotImplemented
+
+        return self._specs == other._specs
+
+    def __ne__(self, other):
+        if isinstance(other, string_types):
+            other = SpecifierSet(other)
+        elif isinstance(other, _IndividualSpecifier):
+            other = SpecifierSet(str(other))
+        elif not isinstance(other, SpecifierSet):
+            return NotImplemented
+
+        return self._specs != other._specs
+
+    def __len__(self):
+        return len(self._specs)
+
+    def __iter__(self):
+        return iter(self._specs)
+
+    @property
+    def prereleases(self):
+        # If we have been given an explicit prerelease modifier, then we'll
+        # pass that through here.
+        if self._prereleases is not None:
+            return self._prereleases
+
+        # If we don't have any specifiers, and we don't have a forced value,
+        # then we'll just return None since we don't know if this should have
+        # pre-releases or not.
+        if not self._specs:
+            return None
+
+        # Otherwise we'll see if any of the given specifiers accept
+        # prereleases, if any of them do we'll return True, otherwise False.
+        return any(s.prereleases for s in self._specs)
+
+    @prereleases.setter
+    def prereleases(self, value):
+        self._prereleases = value
+
+    def __contains__(self, item):
+        return self.contains(item)
+
+    def contains(self, item, prereleases=None):
+        # Ensure that our item is a Version or LegacyVersion instance.
+        if not isinstance(item, (LegacyVersion, Version)):
+            item = parse(item)
+
+        # Determine if we're forcing a prerelease or not, if we're not forcing
+        # one for this particular filter call, then we'll use whatever the
+        # SpecifierSet thinks for whether or not we should support prereleases.
+        if prereleases is None:
+            prereleases = self.prereleases
+
+        # We can determine if we're going to allow pre-releases by looking to
+        # see if any of the underlying items supports them. If none of them do
+        # and this item is a pre-release then we do not allow it and we can
+        # short circuit that here.
+        # Note: This means that 1.0.dev1 would not be contained in something
+        #       like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
+        if not prereleases and item.is_prerelease:
+            return False
+
+        # We simply dispatch to the underlying specs here to make sure that the
+        # given version is contained within all of them.
+        # Note: This use of all() here means that an empty set of specifiers
+        #       will always return True, this is an explicit design decision.
+        return all(
+            s.contains(item, prereleases=prereleases)
+            for s in self._specs
+        )
+
+    def filter(self, iterable, prereleases=None):
+        # Determine if we're forcing a prerelease or not, if we're not forcing
+        # one for this particular filter call, then we'll use whatever the
+        # SpecifierSet thinks for whether or not we should support prereleases.
+        if prereleases is None:
+            prereleases = self.prereleases
+
+        # If we have any specifiers, then we want to wrap our iterable in the
+        # filter method for each one, this will act as a logical AND amongst
+        # each specifier.
+        if self._specs:
+            for spec in self._specs:
+                iterable = spec.filter(iterable, prereleases=bool(prereleases))
+            return iterable
+        # If we do not have any specifiers, then we need to have a rough filter
+        # which will filter out any pre-releases, unless there are no final
+        # releases, and which will filter out LegacyVersion in general.
+        else:
+            filtered = []
+            found_prereleases = []
+
+            for item in iterable:
+                # Ensure that we some kind of Version class for this item.
+                if not isinstance(item, (LegacyVersion, Version)):
+                    parsed_version = parse(item)
+                else:
+                    parsed_version = item
+
+                # Filter out any item which is parsed as a LegacyVersion
+                if isinstance(parsed_version, LegacyVersion):
+                    continue
+
+                # Store any item which is a pre-release for later unless we've
+                # already found a final version or we are accepting prereleases
+                if parsed_version.is_prerelease and not prereleases:
+                    if not filtered:
+                        found_prereleases.append(item)
+                else:
+                    filtered.append(item)
+
+            # If we've found no items except for pre-releases, then we'll go
+            # ahead and use the pre-releases
+            if not filtered and found_prereleases and prereleases is None:
+                return found_prereleases
+
+            return filtered
diff --git a/pkg_resources/_vendor/packaging/utils.py b/pkg_resources/_vendor/packaging/utils.py
new file mode 100644 (file)
index 0000000..942387c
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import re
+
+
+_canonicalize_regex = re.compile(r"[-_.]+")
+
+
+def canonicalize_name(name):
+    # This is taken from PEP 503.
+    return _canonicalize_regex.sub("-", name).lower()
diff --git a/pkg_resources/_vendor/packaging/version.py b/pkg_resources/_vendor/packaging/version.py
new file mode 100644 (file)
index 0000000..83b5ee8
--- /dev/null
@@ -0,0 +1,393 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+from __future__ import absolute_import, division, print_function
+
+import collections
+import itertools
+import re
+
+from ._structures import Infinity
+
+
+__all__ = [
+    "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
+]
+
+
+_Version = collections.namedtuple(
+    "_Version",
+    ["epoch", "release", "dev", "pre", "post", "local"],
+)
+
+
+def parse(version):
+    """
+    Parse the given version string and return either a :class:`Version` object
+    or a :class:`LegacyVersion` object depending on if the given version is
+    a valid PEP 440 version or a legacy version.
+    """
+    try:
+        return Version(version)
+    except InvalidVersion:
+        return LegacyVersion(version)
+
+
+class InvalidVersion(ValueError):
+    """
+    An invalid version was found, users should refer to PEP 440.
+    """
+
+
+class _BaseVersion(object):
+
+    def __hash__(self):
+        return hash(self._key)
+
+    def __lt__(self, other):
+        return self._compare(other, lambda s, o: s < o)
+
+    def __le__(self, other):
+        return self._compare(other, lambda s, o: s <= o)
+
+    def __eq__(self, other):
+        return self._compare(other, lambda s, o: s == o)
+
+    def __ge__(self, other):
+        return self._compare(other, lambda s, o: s >= o)
+
+    def __gt__(self, other):
+        return self._compare(other, lambda s, o: s > o)
+
+    def __ne__(self, other):
+        return self._compare(other, lambda s, o: s != o)
+
+    def _compare(self, other, method):
+        if not isinstance(other, _BaseVersion):
+            return NotImplemented
+
+        return method(self._key, other._key)
+
+
+class LegacyVersion(_BaseVersion):
+
+    def __init__(self, version):
+        self._version = str(version)
+        self._key = _legacy_cmpkey(self._version)
+
+    def __str__(self):
+        return self._version
+
+    def __repr__(self):
+        return "<LegacyVersion({0})>".format(repr(str(self)))
+
+    @property
+    def public(self):
+        return self._version
+
+    @property
+    def base_version(self):
+        return self._version
+
+    @property
+    def local(self):
+        return None
+
+    @property
+    def is_prerelease(self):
+        return False
+
+    @property
+    def is_postrelease(self):
+        return False
+
+
+_legacy_version_component_re = re.compile(
+    r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
+)
+
+_legacy_version_replacement_map = {
+    "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
+}
+
+
+def _parse_version_parts(s):
+    for part in _legacy_version_component_re.split(s):
+        part = _legacy_version_replacement_map.get(part, part)
+
+        if not part or part == ".":
+            continue
+
+        if part[:1] in "0123456789":
+            # pad for numeric comparison
+            yield part.zfill(8)
+        else:
+            yield "*" + part
+
+    # ensure that alpha/beta/candidate are before final
+    yield "*final"
+
+
+def _legacy_cmpkey(version):
+    # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
+    # greater than or equal to 0. This will effectively put the LegacyVersion,
+    # which uses the defacto standard originally implemented by setuptools,
+    # as before all PEP 440 versions.
+    epoch = -1
+
+    # This scheme is taken from pkg_resources.parse_version setuptools prior to
+    # it's adoption of the packaging library.
+    parts = []
+    for part in _parse_version_parts(version.lower()):
+        if part.startswith("*"):
+            # remove "-" before a prerelease tag
+            if part < "*final":
+                while parts and parts[-1] == "*final-":
+                    parts.pop()
+
+            # remove trailing zeros from each series of numeric parts
+            while parts and parts[-1] == "00000000":
+                parts.pop()
+
+        parts.append(part)
+    parts = tuple(parts)
+
+    return epoch, parts
+
+# Deliberately not anchored to the start and end of the string, to make it
+# easier for 3rd party code to reuse
+VERSION_PATTERN = r"""
+    v?
+    (?:
+        (?:(?P<epoch>[0-9]+)!)?                           # epoch
+        (?P<release>[0-9]+(?:\.[0-9]+)*)                  # release segment
+        (?P<pre>                                          # pre-release
+            [-_\.]?
+            (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
+            [-_\.]?
+            (?P<pre_n>[0-9]+)?
+        )?
+        (?P<post>                                         # post release
+            (?:-(?P<post_n1>[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?P<post_l>post|rev|r)
+                [-_\.]?
+                (?P<post_n2>[0-9]+)?
+            )
+        )?
+        (?P<dev>                                          # dev release
+            [-_\.]?
+            (?P<dev_l>dev)
+            [-_\.]?
+            (?P<dev_n>[0-9]+)?
+        )?
+    )
+    (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+
+
+class Version(_BaseVersion):
+
+    _regex = re.compile(
+        r"^\s*" + VERSION_PATTERN + r"\s*$",
+        re.VERBOSE | re.IGNORECASE,
+    )
+
+    def __init__(self, version):
+        # Validate the version and parse it into pieces
+        match = self._regex.search(version)
+        if not match:
+            raise InvalidVersion("Invalid version: '{0}'".format(version))
+
+        # Store the parsed out pieces of the version
+        self._version = _Version(
+            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
+            release=tuple(int(i) for i in match.group("release").split(".")),
+            pre=_parse_letter_version(
+                match.group("pre_l"),
+                match.group("pre_n"),
+            ),
+            post=_parse_letter_version(
+                match.group("post_l"),
+                match.group("post_n1") or match.group("post_n2"),
+            ),
+            dev=_parse_letter_version(
+                match.group("dev_l"),
+                match.group("dev_n"),
+            ),
+            local=_parse_local_version(match.group("local")),
+        )
+
+        # Generate a key which will be used for sorting
+        self._key = _cmpkey(
+            self._version.epoch,
+            self._version.release,
+            self._version.pre,
+            self._version.post,
+            self._version.dev,
+            self._version.local,
+        )
+
+    def __repr__(self):
+        return "<Version({0})>".format(repr(str(self)))
+
+    def __str__(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        # Pre-release
+        if self._version.pre is not None:
+            parts.append("".join(str(x) for x in self._version.pre))
+
+        # Post-release
+        if self._version.post is not None:
+            parts.append(".post{0}".format(self._version.post[1]))
+
+        # Development release
+        if self._version.dev is not None:
+            parts.append(".dev{0}".format(self._version.dev[1]))
+
+        # Local version segment
+        if self._version.local is not None:
+            parts.append(
+                "+{0}".format(".".join(str(x) for x in self._version.local))
+            )
+
+        return "".join(parts)
+
+    @property
+    def public(self):
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        return "".join(parts)
+
+    @property
+    def local(self):
+        version_string = str(self)
+        if "+" in version_string:
+            return version_string.split("+", 1)[1]
+
+    @property
+    def is_prerelease(self):
+        return bool(self._version.dev or self._version.pre)
+
+    @property
+    def is_postrelease(self):
+        return bool(self._version.post)
+
+
+def _parse_letter_version(letter, number):
+    if letter:
+        # We consider there to be an implicit 0 in a pre-release if there is
+        # not a numeral associated with it.
+        if number is None:
+            number = 0
+
+        # We normalize any letters to their lower case form
+        letter = letter.lower()
+
+        # We consider some words to be alternate spellings of other words and
+        # in those cases we want to normalize the spellings to our preferred
+        # spelling.
+        if letter == "alpha":
+            letter = "a"
+        elif letter == "beta":
+            letter = "b"
+        elif letter in ["c", "pre", "preview"]:
+            letter = "rc"
+        elif letter in ["rev", "r"]:
+            letter = "post"
+
+        return letter, int(number)
+    if not letter and number:
+        # We assume if we are given a number, but we are not given a letter
+        # then this is using the implicit post release syntax (e.g. 1.0-1)
+        letter = "post"
+
+        return letter, int(number)
+
+
+_local_version_seperators = re.compile(r"[\._-]")
+
+
+def _parse_local_version(local):
+    """
+    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
+    """
+    if local is not None:
+        return tuple(
+            part.lower() if not part.isdigit() else int(part)
+            for part in _local_version_seperators.split(local)
+        )
+
+
+def _cmpkey(epoch, release, pre, post, dev, local):
+    # When we compare a release version, we want to compare it with all of the
+    # trailing zeros removed. So we'll use a reverse the list, drop all the now
+    # leading zeros until we come to something non zero, then take the rest
+    # re-reverse it back into the correct order and make it a tuple and use
+    # that for our sorting key.
+    release = tuple(
+        reversed(list(
+            itertools.dropwhile(
+                lambda x: x == 0,
+                reversed(release),
+            )
+        ))
+    )
+
+    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
+    # We'll do this by abusing the pre segment, but we _only_ want to do this
+    # if there is not a pre or a post segment. If we have one of those then
+    # the normal sorting rules will handle this case correctly.
+    if pre is None and post is None and dev is not None:
+        pre = -Infinity
+    # Versions without a pre-release (except as noted above) should sort after
+    # those with one.
+    elif pre is None:
+        pre = Infinity
+
+    # Versions without a post segment should sort before those with one.
+    if post is None:
+        post = -Infinity
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        dev = Infinity
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        local = -Infinity
+    else:
+        # Versions with a local segment need that segment parsed to implement
+        # the sorting rules in PEP440.
+        # - Alpha numeric segments sort before numeric segments
+        # - Alpha numeric segments sort lexicographically
+        # - Numeric segments sort numerically
+        # - Shorter versions sort before longer versions when the prefixes
+        #   match exactly
+        local = tuple(
+            (i, "") if isinstance(i, int) else (-Infinity, i)
+            for i in local
+        )
+
+    return epoch, release, pre, post, dev, local
diff --git a/pkg_resources/_vendor/pyparsing.py b/pkg_resources/_vendor/pyparsing.py
new file mode 100644 (file)
index 0000000..a212243
--- /dev/null
@@ -0,0 +1,5696 @@
+# module pyparsing.py\r
+#\r
+# Copyright (c) 2003-2016  Paul T. McGuire\r
+#\r
+# Permission is hereby granted, free of charge, to any person obtaining\r
+# a copy of this software and associated documentation files (the\r
+# "Software"), to deal in the Software without restriction, including\r
+# without limitation the rights to use, copy, modify, merge, publish,\r
+# distribute, sublicense, and/or sell copies of the Software, and to\r
+# permit persons to whom the Software is furnished to do so, subject to\r
+# the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+#\r
+\r
+__doc__ = \\r
+"""\r
+pyparsing module - Classes and methods to define and execute parsing grammars\r
+\r
+The pyparsing module is an alternative approach to creating and executing simple grammars,\r
+vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you\r
+don't need to learn a new syntax for defining grammars or matching expressions - the parsing module\r
+provides a library of classes that you use to construct the grammar directly in Python.\r
+\r
+Here is a program to parse "Hello, World!" (or any greeting of the form \r
+C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements \r
+(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to\r
+L{Literal} expressions)::\r
+\r
+    from pyparsing import Word, alphas\r
+\r
+    # define grammar of a greeting\r
+    greet = Word(alphas) + "," + Word(alphas) + "!"\r
+\r
+    hello = "Hello, World!"\r
+    print (hello, "->", greet.parseString(hello))\r
+\r
+The program outputs the following::\r
+\r
+    Hello, World! -> ['Hello', ',', 'World', '!']\r
+\r
+The Python representation of the grammar is quite readable, owing to the self-explanatory\r
+class names, and the use of '+', '|' and '^' operators.\r
+\r
+The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an\r
+object with named attributes.\r
+\r
+The pyparsing module handles some of the problems that are typically vexing when writing text parsers:\r
+ - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)\r
+ - quoted strings\r
+ - embedded comments\r
+"""\r
+\r
+__version__ = "2.1.10"\r
+__versionTime__ = "07 Oct 2016 01:31 UTC"\r
+__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"\r
+\r
+import string\r
+from weakref import ref as wkref\r
+import copy\r
+import sys\r
+import warnings\r
+import re\r
+import sre_constants\r
+import collections\r
+import pprint\r
+import traceback\r
+import types\r
+from datetime import datetime\r
+\r
+try:\r
+    from _thread import RLock\r
+except ImportError:\r
+    from threading import RLock\r
+\r
+try:\r
+    from collections import OrderedDict as _OrderedDict\r
+except ImportError:\r
+    try:\r
+        from ordereddict import OrderedDict as _OrderedDict\r
+    except ImportError:\r
+        _OrderedDict = None\r
+\r
+#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )\r
+\r
+__all__ = [\r
+'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',\r
+'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',\r
+'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',\r
+'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',\r
+'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',\r
+'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', \r
+'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',\r
+'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',\r
+'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',\r
+'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',\r
+'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno',\r
+'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',\r
+'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',\r
+'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', \r
+'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',\r
+'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',\r
+'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass',\r
+'CloseMatch', 'tokenMap', 'pyparsing_common',\r
+]\r
+\r
+system_version = tuple(sys.version_info)[:3]\r
+PY_3 = system_version[0] == 3\r
+if PY_3:\r
+    _MAX_INT = sys.maxsize\r
+    basestring = str\r
+    unichr = chr\r
+    _ustr = str\r
+\r
+    # build list of single arg builtins, that can be used as parse actions\r
+    singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max]\r
+\r
+else:\r
+    _MAX_INT = sys.maxint\r
+    range = xrange\r
+\r
+    def _ustr(obj):\r
+        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries\r
+           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It\r
+           then < returns the unicode object | encodes it with the default encoding | ... >.\r
+        """\r
+        if isinstance(obj,unicode):\r
+            return obj\r
+\r
+        try:\r
+            # If this works, then _ustr(obj) has the same behaviour as str(obj), so\r
+            # it won't break any existing code.\r
+            return str(obj)\r
+\r
+        except UnicodeEncodeError:\r
+            # Else encode it\r
+            ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace')\r
+            xmlcharref = Regex('&#\d+;')\r
+            xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:])\r
+            return xmlcharref.transformString(ret)\r
+\r
+    # build list of single arg builtins, tolerant of Python version, that can be used as parse actions\r
+    singleArgBuiltins = []\r
+    import __builtin__\r
+    for fname in "sum len sorted reversed list tuple set any all min max".split():\r
+        try:\r
+            singleArgBuiltins.append(getattr(__builtin__,fname))\r
+        except AttributeError:\r
+            continue\r
+            \r
+_generatorType = type((y for y in range(1)))\r
\r
+def _xml_escape(data):\r
+    """Escape &, <, >, ", ', etc. in a string of data."""\r
+\r
+    # ampersand must be replaced first\r
+    from_symbols = '&><"\''\r
+    to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split())\r
+    for from_,to_ in zip(from_symbols, to_symbols):\r
+        data = data.replace(from_, to_)\r
+    return data\r
+\r
+class _Constants(object):\r
+    pass\r
+\r
+alphas     = string.ascii_uppercase + string.ascii_lowercase\r
+nums       = "0123456789"\r
+hexnums    = nums + "ABCDEFabcdef"\r
+alphanums  = alphas + nums\r
+_bslash    = chr(92)\r
+printables = "".join(c for c in string.printable if c not in string.whitespace)\r
+\r
+class ParseBaseException(Exception):\r
+    """base exception class for all parsing runtime exceptions"""\r
+    # Performance tuning: we construct a *lot* of these, so keep this\r
+    # constructor as small and fast as possible\r
+    def __init__( self, pstr, loc=0, msg=None, elem=None ):\r
+        self.loc = loc\r
+        if msg is None:\r
+            self.msg = pstr\r
+            self.pstr = ""\r
+        else:\r
+            self.msg = msg\r
+            self.pstr = pstr\r
+        self.parserElement = elem\r
+        self.args = (pstr, loc, msg)\r
+\r
+    @classmethod\r
+    def _from_exception(cls, pe):\r
+        """\r
+        internal factory method to simplify creating one type of ParseException \r
+        from another - avoids having __init__ signature conflicts among subclasses\r
+        """\r
+        return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement)\r
+\r
+    def __getattr__( self, aname ):\r
+        """supported attributes by name are:\r
+            - lineno - returns the line number of the exception text\r
+            - col - returns the column number of the exception text\r
+            - line - returns the line containing the exception text\r
+        """\r
+        if( aname == "lineno" ):\r
+            return lineno( self.loc, self.pstr )\r
+        elif( aname in ("col", "column") ):\r
+            return col( self.loc, self.pstr )\r
+        elif( aname == "line" ):\r
+            return line( self.loc, self.pstr )\r
+        else:\r
+            raise AttributeError(aname)\r
+\r
+    def __str__( self ):\r
+        return "%s (at char %d), (line:%d, col:%d)" % \\r
+                ( self.msg, self.loc, self.lineno, self.column )\r
+    def __repr__( self ):\r
+        return _ustr(self)\r
+    def markInputline( self, markerString = ">!<" ):\r
+        """Extracts the exception line from the input string, and marks\r
+           the location of the exception with a special symbol.\r
+        """\r
+        line_str = self.line\r
+        line_column = self.column - 1\r
+        if markerString:\r
+            line_str = "".join((line_str[:line_column],\r
+                                markerString, line_str[line_column:]))\r
+        return line_str.strip()\r
+    def __dir__(self):\r
+        return "lineno col line".split() + dir(type(self))\r
+\r
+class ParseException(ParseBaseException):\r
+    """\r
+    Exception thrown when parse expressions don't match class;\r
+    supported attributes by name are:\r
+     - lineno - returns the line number of the exception text\r
+     - col - returns the column number of the exception text\r
+     - line - returns the line containing the exception text\r
+        \r
+    Example::\r
+        try:\r
+            Word(nums).setName("integer").parseString("ABC")\r
+        except ParseException as pe:\r
+            print(pe)\r
+            print("column: {}".format(pe.col))\r
+            \r
+    prints::\r
+       Expected integer (at char 0), (line:1, col:1)\r
+        column: 1\r
+    """\r
+    pass\r
+\r
+class ParseFatalException(ParseBaseException):\r
+    """user-throwable exception thrown when inconsistent parse content\r
+       is found; stops all parsing immediately"""\r
+    pass\r
+\r
+class ParseSyntaxException(ParseFatalException):\r
+    """just like L{ParseFatalException}, but thrown internally when an\r
+       L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop \r
+       immediately because an unbacktrackable syntax error has been found"""\r
+    pass\r
+\r
+#~ class ReparseException(ParseBaseException):\r
+    #~ """Experimental class - parse actions can raise this exception to cause\r
+       #~ pyparsing to reparse the input string:\r
+        #~ - with a modified input string, and/or\r
+        #~ - with a modified start location\r
+       #~ Set the values of the ReparseException in the constructor, and raise the\r
+       #~ exception in a parse action to cause pyparsing to use the new string/location.\r
+       #~ Setting the values as None causes no change to be made.\r
+       #~ """\r
+    #~ def __init_( self, newstring, restartLoc ):\r
+        #~ self.newParseText = newstring\r
+        #~ self.reparseLoc = restartLoc\r
+\r
+class RecursiveGrammarException(Exception):\r
+    """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive"""\r
+    def __init__( self, parseElementList ):\r
+        self.parseElementTrace = parseElementList\r
+\r
+    def __str__( self ):\r
+        return "RecursiveGrammarException: %s" % self.parseElementTrace\r
+\r
+class _ParseResultsWithOffset(object):\r
+    def __init__(self,p1,p2):\r
+        self.tup = (p1,p2)\r
+    def __getitem__(self,i):\r
+        return self.tup[i]\r
+    def __repr__(self):\r
+        return repr(self.tup[0])\r
+    def setOffset(self,i):\r
+        self.tup = (self.tup[0],i)\r
+\r
+class ParseResults(object):\r
+    """\r
+    Structured parse results, to provide multiple means of access to the parsed data:\r
+       - as a list (C{len(results)})\r
+       - by list index (C{results[0], results[1]}, etc.)\r
+       - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName})\r
+\r
+    Example::\r
+        integer = Word(nums)\r
+        date_str = (integer.setResultsName("year") + '/' \r
+                        + integer.setResultsName("month") + '/' \r
+                        + integer.setResultsName("day"))\r
+        # equivalent form:\r
+        # date_str = integer("year") + '/' + integer("month") + '/' + integer("day")\r
+\r
+        # parseString returns a ParseResults object\r
+        result = date_str.parseString("1999/12/31")\r
+\r
+        def test(s, fn=repr):\r
+            print("%s -> %s" % (s, fn(eval(s))))\r
+        test("list(result)")\r
+        test("result[0]")\r
+        test("result['month']")\r
+        test("result.day")\r
+        test("'month' in result")\r
+        test("'minutes' in result")\r
+        test("result.dump()", str)\r
+    prints::\r
+        list(result) -> ['1999', '/', '12', '/', '31']\r
+        result[0] -> '1999'\r
+        result['month'] -> '12'\r
+        result.day -> '31'\r
+        'month' in result -> True\r
+        'minutes' in result -> False\r
+        result.dump() -> ['1999', '/', '12', '/', '31']\r
+        - day: 31\r
+        - month: 12\r
+        - year: 1999\r
+    """\r
+    def __new__(cls, toklist=None, name=None, asList=True, modal=True ):\r
+        if isinstance(toklist, cls):\r
+            return toklist\r
+        retobj = object.__new__(cls)\r
+        retobj.__doinit = True\r
+        return retobj\r
+\r
+    # Performance tuning: we construct a *lot* of these, so keep this\r
+    # constructor as small and fast as possible\r
+    def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ):\r
+        if self.__doinit:\r
+            self.__doinit = False\r
+            self.__name = None\r
+            self.__parent = None\r
+            self.__accumNames = {}\r
+            self.__asList = asList\r
+            self.__modal = modal\r
+            if toklist is None:\r
+                toklist = []\r
+            if isinstance(toklist, list):\r
+                self.__toklist = toklist[:]\r
+            elif isinstance(toklist, _generatorType):\r
+                self.__toklist = list(toklist)\r
+            else:\r
+                self.__toklist = [toklist]\r
+            self.__tokdict = dict()\r
+\r
+        if name is not None and name:\r
+            if not modal:\r
+                self.__accumNames[name] = 0\r
+            if isinstance(name,int):\r
+                name = _ustr(name) # will always return a str, but use _ustr for consistency\r
+            self.__name = name\r
+            if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])):\r
+                if isinstance(toklist,basestring):\r
+                    toklist = [ toklist ]\r
+                if asList:\r
+                    if isinstance(toklist,ParseResults):\r
+                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)\r
+                    else:\r
+                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)\r
+                    self[name].__name = name\r
+                else:\r
+                    try:\r
+                        self[name] = toklist[0]\r
+                    except (KeyError,TypeError,IndexError):\r
+                        self[name] = toklist\r
+\r
+    def __getitem__( self, i ):\r
+        if isinstance( i, (int,slice) ):\r
+            return self.__toklist[i]\r
+        else:\r
+            if i not in self.__accumNames:\r
+                return self.__tokdict[i][-1][0]\r
+            else:\r
+                return ParseResults([ v[0] for v in self.__tokdict[i] ])\r
+\r
+    def __setitem__( self, k, v, isinstance=isinstance ):\r
+        if isinstance(v,_ParseResultsWithOffset):\r
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]\r
+            sub = v[0]\r
+        elif isinstance(k,(int,slice)):\r
+            self.__toklist[k] = v\r
+            sub = v\r
+        else:\r
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]\r
+            sub = v\r
+        if isinstance(sub,ParseResults):\r
+            sub.__parent = wkref(self)\r
+\r
+    def __delitem__( self, i ):\r
+        if isinstance(i,(int,slice)):\r
+            mylen = len( self.__toklist )\r
+            del self.__toklist[i]\r
+\r
+            # convert int to slice\r
+            if isinstance(i, int):\r
+                if i < 0:\r
+                    i += mylen\r
+                i = slice(i, i+1)\r
+            # get removed indices\r
+            removed = list(range(*i.indices(mylen)))\r
+            removed.reverse()\r
+            # fixup indices in token dictionary\r
+            for name,occurrences in self.__tokdict.items():\r
+                for j in removed:\r
+                    for k, (value, position) in enumerate(occurrences):\r
+                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))\r
+        else:\r
+            del self.__tokdict[i]\r
+\r
+    def __contains__( self, k ):\r
+        return k in self.__tokdict\r
+\r
+    def __len__( self ): return len( self.__toklist )\r
+    def __bool__(self): return ( not not self.__toklist )\r
+    __nonzero__ = __bool__\r
+    def __iter__( self ): return iter( self.__toklist )\r
+    def __reversed__( self ): return iter( self.__toklist[::-1] )\r
+    def _iterkeys( self ):\r
+        if hasattr(self.__tokdict, "iterkeys"):\r
+            return self.__tokdict.iterkeys()\r
+        else:\r
+            return iter(self.__tokdict)\r
+\r
+    def _itervalues( self ):\r
+        return (self[k] for k in self._iterkeys())\r
+            \r
+    def _iteritems( self ):\r
+        return ((k, self[k]) for k in self._iterkeys())\r
+\r
+    if PY_3:\r
+        keys = _iterkeys       \r
+        """Returns an iterator of all named result keys (Python 3.x only)."""\r
+\r
+        values = _itervalues\r
+        """Returns an iterator of all named result values (Python 3.x only)."""\r
+\r
+        items = _iteritems\r
+        """Returns an iterator of all named result key-value tuples (Python 3.x only)."""\r
+\r
+    else:\r
+        iterkeys = _iterkeys\r
+        """Returns an iterator of all named result keys (Python 2.x only)."""\r
+\r
+        itervalues = _itervalues\r
+        """Returns an iterator of all named result values (Python 2.x only)."""\r
+\r
+        iteritems = _iteritems\r
+        """Returns an iterator of all named result key-value tuples (Python 2.x only)."""\r
+\r
+        def keys( self ):\r
+            """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x)."""\r
+            return list(self.iterkeys())\r
+\r
+        def values( self ):\r
+            """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x)."""\r
+            return list(self.itervalues())\r
+                \r
+        def items( self ):\r
+            """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x)."""\r
+            return list(self.iteritems())\r
+\r
+    def haskeys( self ):\r
+        """Since keys() returns an iterator, this method is helpful in bypassing\r
+           code that looks for the existence of any defined results names."""\r
+        return bool(self.__tokdict)\r
+        \r
+    def pop( self, *args, **kwargs):\r
+        """\r
+        Removes and returns item at specified index (default=C{last}).\r
+        Supports both C{list} and C{dict} semantics for C{pop()}. If passed no\r
+        argument or an integer argument, it will use C{list} semantics\r
+        and pop tokens from the list of parsed tokens. If passed a \r
+        non-integer argument (most likely a string), it will use C{dict}\r
+        semantics and pop the corresponding value from any defined \r
+        results names. A second default return value argument is \r
+        supported, just as in C{dict.pop()}.\r
+\r
+        Example::\r
+            def remove_first(tokens):\r
+                tokens.pop(0)\r
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']\r
+            print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321']\r
+\r
+            label = Word(alphas)\r
+            patt = label("LABEL") + OneOrMore(Word(nums))\r
+            print(patt.parseString("AAB 123 321").dump())\r
+\r
+            # Use pop() in a parse action to remove named result (note that corresponding value is not\r
+            # removed from list form of results)\r
+            def remove_LABEL(tokens):\r
+                tokens.pop("LABEL")\r
+                return tokens\r
+            patt.addParseAction(remove_LABEL)\r
+            print(patt.parseString("AAB 123 321").dump())\r
+        prints::\r
+            ['AAB', '123', '321']\r
+            - LABEL: AAB\r
+\r
+            ['AAB', '123', '321']\r
+        """\r
+        if not args:\r
+            args = [-1]\r
+        for k,v in kwargs.items():\r
+            if k == 'default':\r
+                args = (args[0], v)\r
+            else:\r
+                raise TypeError("pop() got an unexpected keyword argument '%s'" % k)\r
+        if (isinstance(args[0], int) or \r
+                        len(args) == 1 or \r
+                        args[0] in self):\r
+            index = args[0]\r
+            ret = self[index]\r
+            del self[index]\r
+            return ret\r
+        else:\r
+            defaultvalue = args[1]\r
+            return defaultvalue\r
+\r
+    def get(self, key, defaultValue=None):\r
+        """\r
+        Returns named result matching the given key, or if there is no\r
+        such name, then returns the given C{defaultValue} or C{None} if no\r
+        C{defaultValue} is specified.\r
+\r
+        Similar to C{dict.get()}.\r
+        \r
+        Example::\r
+            integer = Word(nums)\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           \r
+\r
+            result = date_str.parseString("1999/12/31")\r
+            print(result.get("year")) # -> '1999'\r
+            print(result.get("hour", "not specified")) # -> 'not specified'\r
+            print(result.get("hour")) # -> None\r
+        """\r
+        if key in self:\r
+            return self[key]\r
+        else:\r
+            return defaultValue\r
+\r
+    def insert( self, index, insStr ):\r
+        """\r
+        Inserts new element at location index in the list of parsed tokens.\r
+        \r
+        Similar to C{list.insert()}.\r
+\r
+        Example::\r
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']\r
+\r
+            # use a parse action to insert the parse location in the front of the parsed results\r
+            def insert_locn(locn, tokens):\r
+                tokens.insert(0, locn)\r
+            print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321']\r
+        """\r
+        self.__toklist.insert(index, insStr)\r
+        # fixup indices in token dictionary\r
+        for name,occurrences in self.__tokdict.items():\r
+            for k, (value, position) in enumerate(occurrences):\r
+                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))\r
+\r
+    def append( self, item ):\r
+        """\r
+        Add single element to end of ParseResults list of elements.\r
+\r
+        Example::\r
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']\r
+            \r
+            # use a parse action to compute the sum of the parsed integers, and add it to the end\r
+            def append_sum(tokens):\r
+                tokens.append(sum(map(int, tokens)))\r
+            print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444]\r
+        """\r
+        self.__toklist.append(item)\r
+\r
+    def extend( self, itemseq ):\r
+        """\r
+        Add sequence of elements to end of ParseResults list of elements.\r
+\r
+        Example::\r
+            patt = OneOrMore(Word(alphas))\r
+            \r
+            # use a parse action to append the reverse of the matched strings, to make a palindrome\r
+            def make_palindrome(tokens):\r
+                tokens.extend(reversed([t[::-1] for t in tokens]))\r
+                return ''.join(tokens)\r
+            print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl'\r
+        """\r
+        if isinstance(itemseq, ParseResults):\r
+            self += itemseq\r
+        else:\r
+            self.__toklist.extend(itemseq)\r
+\r
+    def clear( self ):\r
+        """\r
+        Clear all elements and results names.\r
+        """\r
+        del self.__toklist[:]\r
+        self.__tokdict.clear()\r
+\r
+    def __getattr__( self, name ):\r
+        try:\r
+            return self[name]\r
+        except KeyError:\r
+            return ""\r
+            \r
+        if name in self.__tokdict:\r
+            if name not in self.__accumNames:\r
+                return self.__tokdict[name][-1][0]\r
+            else:\r
+                return ParseResults([ v[0] for v in self.__tokdict[name] ])\r
+        else:\r
+            return ""\r
+\r
+    def __add__( self, other ):\r
+        ret = self.copy()\r
+        ret += other\r
+        return ret\r
+\r
+    def __iadd__( self, other ):\r
+        if other.__tokdict:\r
+            offset = len(self.__toklist)\r
+            addoffset = lambda a: offset if a<0 else a+offset\r
+            otheritems = other.__tokdict.items()\r
+            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )\r
+                                for (k,vlist) in otheritems for v in vlist]\r
+            for k,v in otherdictitems:\r
+                self[k] = v\r
+                if isinstance(v[0],ParseResults):\r
+                    v[0].__parent = wkref(self)\r
+            \r
+        self.__toklist += other.__toklist\r
+        self.__accumNames.update( other.__accumNames )\r
+        return self\r
+\r
+    def __radd__(self, other):\r
+        if isinstance(other,int) and other == 0:\r
+            # useful for merging many ParseResults using sum() builtin\r
+            return self.copy()\r
+        else:\r
+            # this may raise a TypeError - so be it\r
+            return other + self\r
+        \r
+    def __repr__( self ):\r
+        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )\r
+\r
+    def __str__( self ):\r
+        return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']'\r
+\r
+    def _asStringList( self, sep='' ):\r
+        out = []\r
+        for item in self.__toklist:\r
+            if out and sep:\r
+                out.append(sep)\r
+            if isinstance( item, ParseResults ):\r
+                out += item._asStringList()\r
+            else:\r
+                out.append( _ustr(item) )\r
+        return out\r
+\r
+    def asList( self ):\r
+        """\r
+        Returns the parse results as a nested list of matching tokens, all converted to strings.\r
+\r
+        Example::\r
+            patt = OneOrMore(Word(alphas))\r
+            result = patt.parseString("sldkj lsdkj sldkj")\r
+            # even though the result prints in string-like form, it is actually a pyparsing ParseResults\r
+            print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj']\r
+            \r
+            # Use asList() to create an actual list\r
+            result_list = result.asList()\r
+            print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj']\r
+        """\r
+        return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist]\r
+\r
+    def asDict( self ):\r
+        """\r
+        Returns the named parse results as a nested dictionary.\r
+\r
+        Example::\r
+            integer = Word(nums)\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")\r
+            \r
+            result = date_str.parseString('12/31/1999')\r
+            print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]})\r
+            \r
+            result_dict = result.asDict()\r
+            print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'}\r
+\r
+            # even though a ParseResults supports dict-like access, sometime you just need to have a dict\r
+            import json\r
+            print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable\r
+            print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"}\r
+        """\r
+        if PY_3:\r
+            item_fn = self.items\r
+        else:\r
+            item_fn = self.iteritems\r
+            \r
+        def toItem(obj):\r
+            if isinstance(obj, ParseResults):\r
+                if obj.haskeys():\r
+                    return obj.asDict()\r
+                else:\r
+                    return [toItem(v) for v in obj]\r
+            else:\r
+                return obj\r
+                \r
+        return dict((k,toItem(v)) for k,v in item_fn())\r
+\r
+    def copy( self ):\r
+        """\r
+        Returns a new copy of a C{ParseResults} object.\r
+        """\r
+        ret = ParseResults( self.__toklist )\r
+        ret.__tokdict = self.__tokdict.copy()\r
+        ret.__parent = self.__parent\r
+        ret.__accumNames.update( self.__accumNames )\r
+        ret.__name = self.__name\r
+        return ret\r
+\r
+    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):\r
+        """\r
+        (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.\r
+        """\r
+        nl = "\n"\r
+        out = []\r
+        namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items()\r
+                                                            for v in vlist)\r
+        nextLevelIndent = indent + "  "\r
+\r
+        # collapse out indents if formatting is not desired\r
+        if not formatted:\r
+            indent = ""\r
+            nextLevelIndent = ""\r
+            nl = ""\r
+\r
+        selfTag = None\r
+        if doctag is not None:\r
+            selfTag = doctag\r
+        else:\r
+            if self.__name:\r
+                selfTag = self.__name\r
+\r
+        if not selfTag:\r
+            if namedItemsOnly:\r
+                return ""\r
+            else:\r
+                selfTag = "ITEM"\r
+\r
+        out += [ nl, indent, "<", selfTag, ">" ]\r
+\r
+        for i,res in enumerate(self.__toklist):\r
+            if isinstance(res,ParseResults):\r
+                if i in namedItems:\r
+                    out += [ res.asXML(namedItems[i],\r
+                                        namedItemsOnly and doctag is None,\r
+                                        nextLevelIndent,\r
+                                        formatted)]\r
+                else:\r
+                    out += [ res.asXML(None,\r
+                                        namedItemsOnly and doctag is None,\r
+                                        nextLevelIndent,\r
+                                        formatted)]\r
+            else:\r
+                # individual token, see if there is a name for it\r
+                resTag = None\r
+                if i in namedItems:\r
+                    resTag = namedItems[i]\r
+                if not resTag:\r
+                    if namedItemsOnly:\r
+                        continue\r
+                    else:\r
+                        resTag = "ITEM"\r
+                xmlBodyText = _xml_escape(_ustr(res))\r
+                out += [ nl, nextLevelIndent, "<", resTag, ">",\r
+                                                xmlBodyText,\r
+                                                "</", resTag, ">" ]\r
+\r
+        out += [ nl, indent, "</", selfTag, ">" ]\r
+        return "".join(out)\r
+\r
+    def __lookup(self,sub):\r
+        for k,vlist in self.__tokdict.items():\r
+            for v,loc in vlist:\r
+                if sub is v:\r
+                    return k\r
+        return None\r
+\r
+    def getName(self):\r
+        """\r
+        Returns the results name for this token expression. Useful when several \r
+        different expressions might match at a particular location.\r
+\r
+        Example::\r
+            integer = Word(nums)\r
+            ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d")\r
+            house_number_expr = Suppress('#') + Word(nums, alphanums)\r
+            user_data = (Group(house_number_expr)("house_number") \r
+                        | Group(ssn_expr)("ssn")\r
+                        | Group(integer)("age"))\r
+            user_info = OneOrMore(user_data)\r
+            \r
+            result = user_info.parseString("22 111-22-3333 #221B")\r
+            for item in result:\r
+                print(item.getName(), ':', item[0])\r
+        prints::\r
+            age : 22\r
+            ssn : 111-22-3333\r
+            house_number : 221B\r
+        """\r
+        if self.__name:\r
+            return self.__name\r
+        elif self.__parent:\r
+            par = self.__parent()\r
+            if par:\r
+                return par.__lookup(self)\r
+            else:\r
+                return None\r
+        elif (len(self) == 1 and\r
+               len(self.__tokdict) == 1 and\r
+               next(iter(self.__tokdict.values()))[0][1] in (0,-1)):\r
+            return next(iter(self.__tokdict.keys()))\r
+        else:\r
+            return None\r
+\r
+    def dump(self, indent='', depth=0, full=True):\r
+        """\r
+        Diagnostic method for listing out the contents of a C{ParseResults}.\r
+        Accepts an optional C{indent} argument so that this string can be embedded\r
+        in a nested display of other data.\r
+\r
+        Example::\r
+            integer = Word(nums)\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")\r
+            \r
+            result = date_str.parseString('12/31/1999')\r
+            print(result.dump())\r
+        prints::\r
+            ['12', '/', '31', '/', '1999']\r
+            - day: 1999\r
+            - month: 31\r
+            - year: 12\r
+        """\r
+        out = []\r
+        NL = '\n'\r
+        out.append( indent+_ustr(self.asList()) )\r
+        if full:\r
+            if self.haskeys():\r
+                items = sorted((str(k), v) for k,v in self.items())\r
+                for k,v in items:\r
+                    if out:\r
+                        out.append(NL)\r
+                    out.append( "%s%s- %s: " % (indent,('  '*depth), k) )\r
+                    if isinstance(v,ParseResults):\r
+                        if v:\r
+                            out.append( v.dump(indent,depth+1) )\r
+                        else:\r
+                            out.append(_ustr(v))\r
+                    else:\r
+                        out.append(repr(v))\r
+            elif any(isinstance(vv,ParseResults) for vv in self):\r
+                v = self\r
+                for i,vv in enumerate(v):\r
+                    if isinstance(vv,ParseResults):\r
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),vv.dump(indent,depth+1) ))\r
+                    else:\r
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),_ustr(vv)))\r
+            \r
+        return "".join(out)\r
+\r
+    def pprint(self, *args, **kwargs):\r
+        """\r
+        Pretty-printer for parsed results as a list, using the C{pprint} module.\r
+        Accepts additional positional or keyword args as defined for the \r
+        C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint})\r
+\r
+        Example::\r
+            ident = Word(alphas, alphanums)\r
+            num = Word(nums)\r
+            func = Forward()\r
+            term = ident | num | Group('(' + func + ')')\r
+            func <<= ident + Group(Optional(delimitedList(term)))\r
+            result = func.parseString("fna a,b,(fnb c,d,200),100")\r
+            result.pprint(width=40)\r
+        prints::\r
+            ['fna',\r
+             ['a',\r
+              'b',\r
+              ['(', 'fnb', ['c', 'd', '200'], ')'],\r
+              '100']]\r
+        """\r
+        pprint.pprint(self.asList(), *args, **kwargs)\r
+\r
+    # add support for pickle protocol\r
+    def __getstate__(self):\r
+        return ( self.__toklist,\r
+                 ( self.__tokdict.copy(),\r
+                   self.__parent is not None and self.__parent() or None,\r
+                   self.__accumNames,\r
+                   self.__name ) )\r
+\r
+    def __setstate__(self,state):\r
+        self.__toklist = state[0]\r
+        (self.__tokdict,\r
+         par,\r
+         inAccumNames,\r
+         self.__name) = state[1]\r
+        self.__accumNames = {}\r
+        self.__accumNames.update(inAccumNames)\r
+        if par is not None:\r
+            self.__parent = wkref(par)\r
+        else:\r
+            self.__parent = None\r
+\r
+    def __getnewargs__(self):\r
+        return self.__toklist, self.__name, self.__asList, self.__modal\r
+\r
+    def __dir__(self):\r
+        return (dir(type(self)) + list(self.keys()))\r
+\r
+collections.MutableMapping.register(ParseResults)\r
+\r
+def col (loc,strg):\r
+    """Returns current column within a string, counting newlines as line separators.\r
+   The first column is number 1.\r
+\r
+   Note: the default parsing behavior is to expand tabs in the input string\r
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information\r
+   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a\r
+   consistent view of the parsed string, the parse location, and line and column\r
+   positions within the parsed string.\r
+   """\r
+    s = strg\r
+    return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc)\r
+\r
+def lineno(loc,strg):\r
+    """Returns current line number within a string, counting newlines as line separators.\r
+   The first line is number 1.\r
+\r
+   Note: the default parsing behavior is to expand tabs in the input string\r
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information\r
+   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a\r
+   consistent view of the parsed string, the parse location, and line and column\r
+   positions within the parsed string.\r
+   """\r
+    return strg.count("\n",0,loc) + 1\r
+\r
+def line( loc, strg ):\r
+    """Returns the line of text containing loc within a string, counting newlines as line separators.\r
+       """\r
+    lastCR = strg.rfind("\n", 0, loc)\r
+    nextCR = strg.find("\n", loc)\r
+    if nextCR >= 0:\r
+        return strg[lastCR+1:nextCR]\r
+    else:\r
+        return strg[lastCR+1:]\r
+\r
+def _defaultStartDebugAction( instring, loc, expr ):\r
+    print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))\r
+\r
+def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):\r
+    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))\r
+\r
+def _defaultExceptionDebugAction( instring, loc, expr, exc ):\r
+    print ("Exception raised:" + _ustr(exc))\r
+\r
+def nullDebugAction(*args):\r
+    """'Do-nothing' debug action, to suppress debugging output during parsing."""\r
+    pass\r
+\r
+# Only works on Python 3.x - nonlocal is toxic to Python 2 installs\r
+#~ 'decorator to trim function calls to match the arity of the target'\r
+#~ def _trim_arity(func, maxargs=3):\r
+    #~ if func in singleArgBuiltins:\r
+        #~ return lambda s,l,t: func(t)\r
+    #~ limit = 0\r
+    #~ foundArity = False\r
+    #~ def wrapper(*args):\r
+        #~ nonlocal limit,foundArity\r
+        #~ while 1:\r
+            #~ try:\r
+                #~ ret = func(*args[limit:])\r
+                #~ foundArity = True\r
+                #~ return ret\r
+            #~ except TypeError:\r
+                #~ if limit == maxargs or foundArity:\r
+                    #~ raise\r
+                #~ limit += 1\r
+                #~ continue\r
+    #~ return wrapper\r
+\r
+# this version is Python 2.x-3.x cross-compatible\r
+'decorator to trim function calls to match the arity of the target'\r
+def _trim_arity(func, maxargs=2):\r
+    if func in singleArgBuiltins:\r
+        return lambda s,l,t: func(t)\r
+    limit = [0]\r
+    foundArity = [False]\r
+    \r
+    # traceback return data structure changed in Py3.5 - normalize back to plain tuples\r
+    if system_version[:2] >= (3,5):\r
+        def extract_stack(limit=0):\r
+            # special handling for Python 3.5.0 - extra deep call stack by 1\r
+            offset = -3 if system_version == (3,5,0) else -2\r
+            frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset]\r
+            return [(frame_summary.filename, frame_summary.lineno)]\r
+        def extract_tb(tb, limit=0):\r
+            frames = traceback.extract_tb(tb, limit=limit)\r
+            frame_summary = frames[-1]\r
+            return [(frame_summary.filename, frame_summary.lineno)]\r
+    else:\r
+        extract_stack = traceback.extract_stack\r
+        extract_tb = traceback.extract_tb\r
+    \r
+    # synthesize what would be returned by traceback.extract_stack at the call to \r
+    # user's parse action 'func', so that we don't incur call penalty at parse time\r
+    \r
+    LINE_DIFF = 6\r
+    # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND \r
+    # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!\r
+    this_line = extract_stack(limit=2)[-1]\r
+    pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF)\r
+\r
+    def wrapper(*args):\r
+        while 1:\r
+            try:\r
+                ret = func(*args[limit[0]:])\r
+                foundArity[0] = True\r
+                return ret\r
+            except TypeError:\r
+                # re-raise TypeErrors if they did not come from our arity testing\r
+                if foundArity[0]:\r
+                    raise\r
+                else:\r
+                    try:\r
+                        tb = sys.exc_info()[-1]\r
+                        if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth:\r
+                            raise\r
+                    finally:\r
+                        del tb\r
+\r
+                if limit[0] <= maxargs:\r
+                    limit[0] += 1\r
+                    continue\r
+                raise\r
+\r
+    # copy func name to wrapper for sensible debug output\r
+    func_name = "<parse action>"\r
+    try:\r
+        func_name = getattr(func, '__name__', \r
+                            getattr(func, '__class__').__name__)\r
+    except Exception:\r
+        func_name = str(func)\r
+    wrapper.__name__ = func_name\r
+\r
+    return wrapper\r
+\r
+class ParserElement(object):\r
+    """Abstract base level parser element class."""\r
+    DEFAULT_WHITE_CHARS = " \n\t\r"\r
+    verbose_stacktrace = False\r
+\r
+    @staticmethod\r
+    def setDefaultWhitespaceChars( chars ):\r
+        r"""\r
+        Overrides the default whitespace chars\r
+\r
+        Example::\r
+            # default whitespace chars are space, <TAB> and newline\r
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']\r
+            \r
+            # change to just treat newline as significant\r
+            ParserElement.setDefaultWhitespaceChars(" \t")\r
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def']\r
+        """\r
+        ParserElement.DEFAULT_WHITE_CHARS = chars\r
+\r
+    @staticmethod\r
+    def inlineLiteralsUsing(cls):\r
+        """\r
+        Set class to be used for inclusion of string literals into a parser.\r
+        \r
+        Example::\r
+            # default literal class used is Literal\r
+            integer = Word(nums)\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           \r
+\r
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']\r
+\r
+\r
+            # change to Suppress\r
+            ParserElement.inlineLiteralsUsing(Suppress)\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           \r
+\r
+            date_str.parseString("1999/12/31")  # -> ['1999', '12', '31']\r
+        """\r
+        ParserElement._literalStringClass = cls\r
+\r
+    def __init__( self, savelist=False ):\r
+        self.parseAction = list()\r
+        self.failAction = None\r
+        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall\r
+        self.strRepr = None\r
+        self.resultsName = None\r
+        self.saveAsList = savelist\r
+        self.skipWhitespace = True\r
+        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS\r
+        self.copyDefaultWhiteChars = True\r
+        self.mayReturnEmpty = False # used when checking for left-recursion\r
+        self.keepTabs = False\r
+        self.ignoreExprs = list()\r
+        self.debug = False\r
+        self.streamlined = False\r
+        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index\r
+        self.errmsg = ""\r
+        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)\r
+        self.debugActions = ( None, None, None ) #custom debug actions\r
+        self.re = None\r
+        self.callPreparse = True # used to avoid redundant calls to preParse\r
+        self.callDuringTry = False\r
+\r
+    def copy( self ):\r
+        """\r
+        Make a copy of this C{ParserElement}.  Useful for defining different parse actions\r
+        for the same parsing pattern, using copies of the original parse element.\r
+        \r
+        Example::\r
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))\r
+            integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K")\r
+            integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")\r
+            \r
+            print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M"))\r
+        prints::\r
+            [5120, 100, 655360, 268435456]\r
+        Equivalent form of C{expr.copy()} is just C{expr()}::\r
+            integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")\r
+        """\r
+        cpy = copy.copy( self )\r
+        cpy.parseAction = self.parseAction[:]\r
+        cpy.ignoreExprs = self.ignoreExprs[:]\r
+        if self.copyDefaultWhiteChars:\r
+            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS\r
+        return cpy\r
+\r
+    def setName( self, name ):\r
+        """\r
+        Define name for this expression, makes debugging and exception messages clearer.\r
+        \r
+        Example::\r
+            Word(nums).parseString("ABC")  # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1)\r
+            Word(nums).setName("integer").parseString("ABC")  # -> Exception: Expected integer (at char 0), (line:1, col:1)\r
+        """\r
+        self.name = name\r
+        self.errmsg = "Expected " + self.name\r
+        if hasattr(self,"exception"):\r
+            self.exception.msg = self.errmsg\r
+        return self\r
+\r
+    def setResultsName( self, name, listAllMatches=False ):\r
+        """\r
+        Define name for referencing matching tokens as a nested attribute\r
+        of the returned parse results.\r
+        NOTE: this returns a *copy* of the original C{ParserElement} object;\r
+        this is so that the client can define a basic element, such as an\r
+        integer, and reference it in multiple places with different names.\r
+\r
+        You can also set results names using the abbreviated syntax,\r
+        C{expr("name")} in place of C{expr.setResultsName("name")} - \r
+        see L{I{__call__}<__call__>}.\r
+\r
+        Example::\r
+            date_str = (integer.setResultsName("year") + '/' \r
+                        + integer.setResultsName("month") + '/' \r
+                        + integer.setResultsName("day"))\r
+\r
+            # equivalent form:\r
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")\r
+        """\r
+        newself = self.copy()\r
+        if name.endswith("*"):\r
+            name = name[:-1]\r
+            listAllMatches=True\r
+        newself.resultsName = name\r
+        newself.modalResults = not listAllMatches\r
+        return newself\r
+\r
+    def setBreak(self,breakFlag = True):\r
+        """Method to invoke the Python pdb debugger when this element is\r
+           about to be parsed. Set C{breakFlag} to True to enable, False to\r
+           disable.\r
+        """\r
+        if breakFlag:\r
+            _parseMethod = self._parse\r
+            def breaker(instring, loc, doActions=True, callPreParse=True):\r
+                import pdb\r
+                pdb.set_trace()\r
+                return _parseMethod( instring, loc, doActions, callPreParse )\r
+            breaker._originalParseMethod = _parseMethod\r
+            self._parse = breaker\r
+        else:\r
+            if hasattr(self._parse,"_originalParseMethod"):\r
+                self._parse = self._parse._originalParseMethod\r
+        return self\r
+\r
+    def setParseAction( self, *fns, **kwargs ):\r
+        """\r
+        Define action to perform when successfully matching parse element definition.\r
+        Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},\r
+        C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:\r
+         - s   = the original string being parsed (see note below)\r
+         - loc = the location of the matching substring\r
+         - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object\r
+        If the functions in fns modify the tokens, they can return them as the return\r
+        value from fn, and the modified list of tokens will replace the original.\r
+        Otherwise, fn does not need to return any value.\r
+\r
+        Optional keyword arguments:\r
+         - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing\r
+\r
+        Note: the default parsing behavior is to expand tabs in the input string\r
+        before starting the parsing process.  See L{I{parseString}<parseString>} for more information\r
+        on parsing strings containing C{<TAB>}s, and suggested methods to maintain a\r
+        consistent view of the parsed string, the parse location, and line and column\r
+        positions within the parsed string.\r
+        \r
+        Example::\r
+            integer = Word(nums)\r
+            date_str = integer + '/' + integer + '/' + integer\r
+\r
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']\r
+\r
+            # use parse action to convert to ints at parse time\r
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))\r
+            date_str = integer + '/' + integer + '/' + integer\r
+\r
+            # note that integer fields are now ints, not strings\r
+            date_str.parseString("1999/12/31")  # -> [1999, '/', 12, '/', 31]\r
+        """\r
+        self.parseAction = list(map(_trim_arity, list(fns)))\r
+        self.callDuringTry = kwargs.get("callDuringTry", False)\r
+        return self\r
+\r
+    def addParseAction( self, *fns, **kwargs ):\r
+        """\r
+        Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}.\r
+        \r
+        See examples in L{I{copy}<copy>}.\r
+        """\r
+        self.parseAction += list(map(_trim_arity, list(fns)))\r
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)\r
+        return self\r
+\r
+    def addCondition(self, *fns, **kwargs):\r
+        """Add a boolean predicate function to expression's list of parse actions. See \r
+        L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, \r
+        functions passed to C{addCondition} need to return boolean success/fail of the condition.\r
+\r
+        Optional keyword arguments:\r
+         - message = define a custom message to be used in the raised exception\r
+         - fatal   = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException\r
+         \r
+        Example::\r
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))\r
+            year_int = integer.copy()\r
+            year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later")\r
+            date_str = year_int + '/' + integer + '/' + integer\r
+\r
+            result = date_str.parseString("1999/12/31")  # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1)\r
+        """\r
+        msg = kwargs.get("message", "failed user-defined condition")\r
+        exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException\r
+        for fn in fns:\r
+            def pa(s,l,t):\r
+                if not bool(_trim_arity(fn)(s,l,t)):\r
+                    raise exc_type(s,l,msg)\r
+            self.parseAction.append(pa)\r
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)\r
+        return self\r
+\r
+    def setFailAction( self, fn ):\r
+        """Define action to perform if parsing fails at this expression.\r
+           Fail acton fn is a callable function that takes the arguments\r
+           C{fn(s,loc,expr,err)} where:\r
+            - s = string being parsed\r
+            - loc = location where expression match was attempted and failed\r
+            - expr = the parse expression that failed\r
+            - err = the exception thrown\r
+           The function returns no value.  It may throw C{L{ParseFatalException}}\r
+           if it is desired to stop parsing immediately."""\r
+        self.failAction = fn\r
+        return self\r
+\r
+    def _skipIgnorables( self, instring, loc ):\r
+        exprsFound = True\r
+        while exprsFound:\r
+            exprsFound = False\r
+            for e in self.ignoreExprs:\r
+                try:\r
+                    while 1:\r
+                        loc,dummy = e._parse( instring, loc )\r
+                        exprsFound = True\r
+                except ParseException:\r
+                    pass\r
+        return loc\r
+\r
+    def preParse( self, instring, loc ):\r
+        if self.ignoreExprs:\r
+            loc = self._skipIgnorables( instring, loc )\r
+\r
+        if self.skipWhitespace:\r
+            wt = self.whiteChars\r
+            instrlen = len(instring)\r
+            while loc < instrlen and instring[loc] in wt:\r
+                loc += 1\r
+\r
+        return loc\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        return loc, []\r
+\r
+    def postParse( self, instring, loc, tokenlist ):\r
+        return tokenlist\r
+\r
+    #~ @profile\r
+    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):\r
+        debugging = ( self.debug ) #and doActions )\r
+\r
+        if debugging or self.failAction:\r
+            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))\r
+            if (self.debugActions[0] ):\r
+                self.debugActions[0]( instring, loc, self )\r
+            if callPreParse and self.callPreparse:\r
+                preloc = self.preParse( instring, loc )\r
+            else:\r
+                preloc = loc\r
+            tokensStart = preloc\r
+            try:\r
+                try:\r
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )\r
+                except IndexError:\r
+                    raise ParseException( instring, len(instring), self.errmsg, self )\r
+            except ParseBaseException as err:\r
+                #~ print ("Exception raised:", err)\r
+                if self.debugActions[2]:\r
+                    self.debugActions[2]( instring, tokensStart, self, err )\r
+                if self.failAction:\r
+                    self.failAction( instring, tokensStart, self, err )\r
+                raise\r
+        else:\r
+            if callPreParse and self.callPreparse:\r
+                preloc = self.preParse( instring, loc )\r
+            else:\r
+                preloc = loc\r
+            tokensStart = preloc\r
+            if self.mayIndexError or loc >= len(instring):\r
+                try:\r
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )\r
+                except IndexError:\r
+                    raise ParseException( instring, len(instring), self.errmsg, self )\r
+            else:\r
+                loc,tokens = self.parseImpl( instring, preloc, doActions )\r
+\r
+        tokens = self.postParse( instring, loc, tokens )\r
+\r
+        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )\r
+        if self.parseAction and (doActions or self.callDuringTry):\r
+            if debugging:\r
+                try:\r
+                    for fn in self.parseAction:\r
+                        tokens = fn( instring, tokensStart, retTokens )\r
+                        if tokens is not None:\r
+                            retTokens = ParseResults( tokens,\r
+                                                      self.resultsName,\r
+                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),\r
+                                                      modal=self.modalResults )\r
+                except ParseBaseException as err:\r
+                    #~ print "Exception raised in user parse action:", err\r
+                    if (self.debugActions[2] ):\r
+                        self.debugActions[2]( instring, tokensStart, self, err )\r
+                    raise\r
+            else:\r
+                for fn in self.parseAction:\r
+                    tokens = fn( instring, tokensStart, retTokens )\r
+                    if tokens is not None:\r
+                        retTokens = ParseResults( tokens,\r
+                                                  self.resultsName,\r
+                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),\r
+                                                  modal=self.modalResults )\r
+\r
+        if debugging:\r
+            #~ print ("Matched",self,"->",retTokens.asList())\r
+            if (self.debugActions[1] ):\r
+                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )\r
+\r
+        return loc, retTokens\r
+\r
+    def tryParse( self, instring, loc ):\r
+        try:\r
+            return self._parse( instring, loc, doActions=False )[0]\r
+        except ParseFatalException:\r
+            raise ParseException( instring, loc, self.errmsg, self)\r
+    \r
+    def canParseNext(self, instring, loc):\r
+        try:\r
+            self.tryParse(instring, loc)\r
+        except (ParseException, IndexError):\r
+            return False\r
+        else:\r
+            return True\r
+\r
+    class _UnboundedCache(object):\r
+        def __init__(self):\r
+            cache = {}\r
+            self.not_in_cache = not_in_cache = object()\r
+\r
+            def get(self, key):\r
+                return cache.get(key, not_in_cache)\r
+\r
+            def set(self, key, value):\r
+                cache[key] = value\r
+\r
+            def clear(self):\r
+                cache.clear()\r
+\r
+            self.get = types.MethodType(get, self)\r
+            self.set = types.MethodType(set, self)\r
+            self.clear = types.MethodType(clear, self)\r
+\r
+    if _OrderedDict is not None:\r
+        class _FifoCache(object):\r
+            def __init__(self, size):\r
+                self.not_in_cache = not_in_cache = object()\r
+\r
+                cache = _OrderedDict()\r
+\r
+                def get(self, key):\r
+                    return cache.get(key, not_in_cache)\r
+\r
+                def set(self, key, value):\r
+                    cache[key] = value\r
+                    if len(cache) > size:\r
+                        cache.popitem(False)\r
+\r
+                def clear(self):\r
+                    cache.clear()\r
+\r
+                self.get = types.MethodType(get, self)\r
+                self.set = types.MethodType(set, self)\r
+                self.clear = types.MethodType(clear, self)\r
+\r
+    else:\r
+        class _FifoCache(object):\r
+            def __init__(self, size):\r
+                self.not_in_cache = not_in_cache = object()\r
+\r
+                cache = {}\r
+                key_fifo = collections.deque([], size)\r
+\r
+                def get(self, key):\r
+                    return cache.get(key, not_in_cache)\r
+\r
+                def set(self, key, value):\r
+                    cache[key] = value\r
+                    if len(cache) > size:\r
+                        cache.pop(key_fifo.popleft(), None)\r
+                    key_fifo.append(key)\r
+\r
+                def clear(self):\r
+                    cache.clear()\r
+                    key_fifo.clear()\r
+\r
+                self.get = types.MethodType(get, self)\r
+                self.set = types.MethodType(set, self)\r
+                self.clear = types.MethodType(clear, self)\r
+\r
+    # argument cache for optimizing repeated calls when backtracking through recursive expressions\r
+    packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail\r
+    packrat_cache_lock = RLock()\r
+    packrat_cache_stats = [0, 0]\r
+\r
+    # this method gets repeatedly called during backtracking with the same arguments -\r
+    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression\r
+    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):\r
+        HIT, MISS = 0, 1\r
+        lookup = (self, instring, loc, callPreParse, doActions)\r
+        with ParserElement.packrat_cache_lock:\r
+            cache = ParserElement.packrat_cache\r
+            value = cache.get(lookup)\r
+            if value is cache.not_in_cache:\r
+                ParserElement.packrat_cache_stats[MISS] += 1\r
+                try:\r
+                    value = self._parseNoCache(instring, loc, doActions, callPreParse)\r
+                except ParseBaseException as pe:\r
+                    # cache a copy of the exception, without the traceback\r
+                    cache.set(lookup, pe.__class__(*pe.args))\r
+                    raise\r
+                else:\r
+                    cache.set(lookup, (value[0], value[1].copy()))\r
+                    return value\r
+            else:\r
+                ParserElement.packrat_cache_stats[HIT] += 1\r
+                if isinstance(value, Exception):\r
+                    raise value\r
+                return (value[0], value[1].copy())\r
+\r
+    _parse = _parseNoCache\r
+\r
+    @staticmethod\r
+    def resetCache():\r
+        ParserElement.packrat_cache.clear()\r
+        ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats)\r
+\r
+    _packratEnabled = False\r
+    @staticmethod\r
+    def enablePackrat(cache_size_limit=128):\r
+        """Enables "packrat" parsing, which adds memoizing to the parsing logic.\r
+           Repeated parse attempts at the same string location (which happens\r
+           often in many complex grammars) can immediately return a cached value,\r
+           instead of re-executing parsing/validating code.  Memoizing is done of\r
+           both valid results and parsing exceptions.\r
+           \r
+           Parameters:\r
+            - cache_size_limit - (default=C{128}) - if an integer value is provided\r
+              will limit the size of the packrat cache; if None is passed, then\r
+              the cache size will be unbounded; if 0 is passed, the cache will\r
+              be effectively disabled.\r
+            \r
+           This speedup may break existing programs that use parse actions that\r
+           have side-effects.  For this reason, packrat parsing is disabled when\r
+           you first import pyparsing.  To activate the packrat feature, your\r
+           program must call the class method C{ParserElement.enablePackrat()}.  If\r
+           your program uses C{psyco} to "compile as you go", you must call\r
+           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,\r
+           Python will crash.  For best results, call C{enablePackrat()} immediately\r
+           after importing pyparsing.\r
+           \r
+           Example::\r
+               import pyparsing\r
+               pyparsing.ParserElement.enablePackrat()\r
+        """\r
+        if not ParserElement._packratEnabled:\r
+            ParserElement._packratEnabled = True\r
+            if cache_size_limit is None:\r
+                ParserElement.packrat_cache = ParserElement._UnboundedCache()\r
+            else:\r
+                ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit)\r
+            ParserElement._parse = ParserElement._parseCache\r
+\r
+    def parseString( self, instring, parseAll=False ):\r
+        """\r
+        Execute the parse expression with the given string.\r
+        This is the main interface to the client code, once the complete\r
+        expression has been built.\r
+\r
+        If you want the grammar to require that the entire input string be\r
+        successfully parsed, then set C{parseAll} to True (equivalent to ending\r
+        the grammar with C{L{StringEnd()}}).\r
+\r
+        Note: C{parseString} implicitly calls C{expandtabs()} on the input string,\r
+        in order to report proper column numbers in parse actions.\r
+        If the input string contains tabs and\r
+        the grammar uses parse actions that use the C{loc} argument to index into the\r
+        string being parsed, you can ensure you have a consistent view of the input\r
+        string by:\r
+         - calling C{parseWithTabs} on your grammar before calling C{parseString}\r
+           (see L{I{parseWithTabs}<parseWithTabs>})\r
+         - define your parse action using the full C{(s,loc,toks)} signature, and\r
+           reference the input string using the parse action's C{s} argument\r
+         - explictly expand the tabs in your input string before calling\r
+           C{parseString}\r
+        \r
+        Example::\r
+            Word('a').parseString('aaaaabaaa')  # -> ['aaaaa']\r
+            Word('a').parseString('aaaaabaaa', parseAll=True)  # -> Exception: Expected end of text\r
+        """\r
+        ParserElement.resetCache()\r
+        if not self.streamlined:\r
+            self.streamline()\r
+            #~ self.saveAsList = True\r
+        for e in self.ignoreExprs:\r
+            e.streamline()\r
+        if not self.keepTabs:\r
+            instring = instring.expandtabs()\r
+        try:\r
+            loc, tokens = self._parse( instring, 0 )\r
+            if parseAll:\r
+                loc = self.preParse( instring, loc )\r
+                se = Empty() + StringEnd()\r
+                se._parse( instring, loc )\r
+        except ParseBaseException as exc:\r
+            if ParserElement.verbose_stacktrace:\r
+                raise\r
+            else:\r
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace\r
+                raise exc\r
+        else:\r
+            return tokens\r
+\r
+    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):\r
+        """\r
+        Scan the input string for expression matches.  Each match will return the\r
+        matching tokens, start location, and end location.  May be called with optional\r
+        C{maxMatches} argument, to clip scanning after 'n' matches are found.  If\r
+        C{overlap} is specified, then overlapping matches will be reported.\r
+\r
+        Note that the start and end locations are reported relative to the string\r
+        being parsed.  See L{I{parseString}<parseString>} for more information on parsing\r
+        strings with embedded tabs.\r
+\r
+        Example::\r
+            source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"\r
+            print(source)\r
+            for tokens,start,end in Word(alphas).scanString(source):\r
+                print(' '*start + '^'*(end-start))\r
+                print(' '*start + tokens[0])\r
+        \r
+        prints::\r
+        \r
+            sldjf123lsdjjkf345sldkjf879lkjsfd987\r
+            ^^^^^\r
+            sldjf\r
+                    ^^^^^^^\r
+                    lsdjjkf\r
+                              ^^^^^^\r
+                              sldkjf\r
+                                       ^^^^^^\r
+                                       lkjsfd\r
+        """\r
+        if not self.streamlined:\r
+            self.streamline()\r
+        for e in self.ignoreExprs:\r
+            e.streamline()\r
+\r
+        if not self.keepTabs:\r
+            instring = _ustr(instring).expandtabs()\r
+        instrlen = len(instring)\r
+        loc = 0\r
+        preparseFn = self.preParse\r
+        parseFn = self._parse\r
+        ParserElement.resetCache()\r
+        matches = 0\r
+        try:\r
+            while loc <= instrlen and matches < maxMatches:\r
+                try:\r
+                    preloc = preparseFn( instring, loc )\r
+                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )\r
+                except ParseException:\r
+                    loc = preloc+1\r
+                else:\r
+                    if nextLoc > loc:\r
+                        matches += 1\r
+                        yield tokens, preloc, nextLoc\r
+                        if overlap:\r
+                            nextloc = preparseFn( instring, loc )\r
+                            if nextloc > loc:\r
+                                loc = nextLoc\r
+                            else:\r
+                                loc += 1\r
+                        else:\r
+                            loc = nextLoc\r
+                    else:\r
+                        loc = preloc+1\r
+        except ParseBaseException as exc:\r
+            if ParserElement.verbose_stacktrace:\r
+                raise\r
+            else:\r
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace\r
+                raise exc\r
+\r
+    def transformString( self, instring ):\r
+        """\r
+        Extension to C{L{scanString}}, to modify matching text with modified tokens that may\r
+        be returned from a parse action.  To use C{transformString}, define a grammar and\r
+        attach a parse action to it that modifies the returned token list.\r
+        Invoking C{transformString()} on a target string will then scan for matches,\r
+        and replace the matched text patterns according to the logic in the parse\r
+        action.  C{transformString()} returns the resulting transformed string.\r
+        \r
+        Example::\r
+            wd = Word(alphas)\r
+            wd.setParseAction(lambda toks: toks[0].title())\r
+            \r
+            print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york."))\r
+        Prints::\r
+            Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York.\r
+        """\r
+        out = []\r
+        lastE = 0\r
+        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to\r
+        # keep string locs straight between transformString and scanString\r
+        self.keepTabs = True\r
+        try:\r
+            for t,s,e in self.scanString( instring ):\r
+                out.append( instring[lastE:s] )\r
+                if t:\r
+                    if isinstance(t,ParseResults):\r
+                        out += t.asList()\r
+                    elif isinstance(t,list):\r
+                        out += t\r
+                    else:\r
+                        out.append(t)\r
+                lastE = e\r
+            out.append(instring[lastE:])\r
+            out = [o for o in out if o]\r
+            return "".join(map(_ustr,_flatten(out)))\r
+        except ParseBaseException as exc:\r
+            if ParserElement.verbose_stacktrace:\r
+                raise\r
+            else:\r
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace\r
+                raise exc\r
+\r
+    def searchString( self, instring, maxMatches=_MAX_INT ):\r
+        """\r
+        Another extension to C{L{scanString}}, simplifying the access to the tokens found\r
+        to match the given parse expression.  May be called with optional\r
+        C{maxMatches} argument, to clip searching after 'n' matches are found.\r
+        \r
+        Example::\r
+            # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters\r
+            cap_word = Word(alphas.upper(), alphas.lower())\r
+            \r
+            print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))\r
+        prints::\r
+            ['More', 'Iron', 'Lead', 'Gold', 'I']\r
+        """\r
+        try:\r
+            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])\r
+        except ParseBaseException as exc:\r
+            if ParserElement.verbose_stacktrace:\r
+                raise\r
+            else:\r
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace\r
+                raise exc\r
+\r
+    def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False):\r
+        """\r
+        Generator method to split a string using the given expression as a separator.\r
+        May be called with optional C{maxsplit} argument, to limit the number of splits;\r
+        and the optional C{includeSeparators} argument (default=C{False}), if the separating\r
+        matching text should be included in the split results.\r
+        \r
+        Example::        \r
+            punc = oneOf(list(".,;:/-!?"))\r
+            print(list(punc.split("This, this?, this sentence, is badly punctuated!")))\r
+        prints::\r
+            ['This', ' this', '', ' this sentence', ' is badly punctuated', '']\r
+        """\r
+        splits = 0\r
+        last = 0\r
+        for t,s,e in self.scanString(instring, maxMatches=maxsplit):\r
+            yield instring[last:s]\r
+            if includeSeparators:\r
+                yield t[0]\r
+            last = e\r
+        yield instring[last:]\r
+\r
+    def __add__(self, other ):\r
+        """\r
+        Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement\r
+        converts them to L{Literal}s by default.\r
+        \r
+        Example::\r
+            greet = Word(alphas) + "," + Word(alphas) + "!"\r
+            hello = "Hello, World!"\r
+            print (hello, "->", greet.parseString(hello))\r
+        Prints::\r
+            Hello, World! -> ['Hello', ',', 'World', '!']\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return And( [ self, other ] )\r
+\r
+    def __radd__(self, other ):\r
+        """\r
+        Implementation of + operator when left operand is not a C{L{ParserElement}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return other + self\r
+\r
+    def __sub__(self, other):\r
+        """\r
+        Implementation of - operator, returns C{L{And}} with error stop\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return And( [ self, And._ErrorStop(), other ] )\r
+\r
+    def __rsub__(self, other ):\r
+        """\r
+        Implementation of - operator when left operand is not a C{L{ParserElement}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return other - self\r
+\r
+    def __mul__(self,other):\r
+        """\r
+        Implementation of * operator, allows use of C{expr * 3} in place of\r
+        C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer\r
+        tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples\r
+        may also include C{None} as in:\r
+         - C{expr*(n,None)} or C{expr*(n,)} is equivalent\r
+              to C{expr*n + L{ZeroOrMore}(expr)}\r
+              (read as "at least n instances of C{expr}")\r
+         - C{expr*(None,n)} is equivalent to C{expr*(0,n)}\r
+              (read as "0 to n instances of C{expr}")\r
+         - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}\r
+         - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}\r
+\r
+        Note that C{expr*(None,n)} does not raise an exception if\r
+        more than n exprs exist in the input stream; that is,\r
+        C{expr*(None,n)} does not enforce a maximum number of expr\r
+        occurrences.  If this behavior is desired, then write\r
+        C{expr*(None,n) + ~expr}\r
+        """\r
+        if isinstance(other,int):\r
+            minElements, optElements = other,0\r
+        elif isinstance(other,tuple):\r
+            other = (other + (None, None))[:2]\r
+            if other[0] is None:\r
+                other = (0, other[1])\r
+            if isinstance(other[0],int) and other[1] is None:\r
+                if other[0] == 0:\r
+                    return ZeroOrMore(self)\r
+                if other[0] == 1:\r
+                    return OneOrMore(self)\r
+                else:\r
+                    return self*other[0] + ZeroOrMore(self)\r
+            elif isinstance(other[0],int) and isinstance(other[1],int):\r
+                minElements, optElements = other\r
+                optElements -= minElements\r
+            else:\r
+                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))\r
+        else:\r
+            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))\r
+\r
+        if minElements < 0:\r
+            raise ValueError("cannot multiply ParserElement by negative value")\r
+        if optElements < 0:\r
+            raise ValueError("second tuple value must be greater or equal to first tuple value")\r
+        if minElements == optElements == 0:\r
+            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")\r
+\r
+        if (optElements):\r
+            def makeOptionalList(n):\r
+                if n>1:\r
+                    return Optional(self + makeOptionalList(n-1))\r
+                else:\r
+                    return Optional(self)\r
+            if minElements:\r
+                if minElements == 1:\r
+                    ret = self + makeOptionalList(optElements)\r
+                else:\r
+                    ret = And([self]*minElements) + makeOptionalList(optElements)\r
+            else:\r
+                ret = makeOptionalList(optElements)\r
+        else:\r
+            if minElements == 1:\r
+                ret = self\r
+            else:\r
+                ret = And([self]*minElements)\r
+        return ret\r
+\r
+    def __rmul__(self, other):\r
+        return self.__mul__(other)\r
+\r
+    def __or__(self, other ):\r
+        """\r
+        Implementation of | operator - returns C{L{MatchFirst}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return MatchFirst( [ self, other ] )\r
+\r
+    def __ror__(self, other ):\r
+        """\r
+        Implementation of | operator when left operand is not a C{L{ParserElement}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return other | self\r
+\r
+    def __xor__(self, other ):\r
+        """\r
+        Implementation of ^ operator - returns C{L{Or}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return Or( [ self, other ] )\r
+\r
+    def __rxor__(self, other ):\r
+        """\r
+        Implementation of ^ operator when left operand is not a C{L{ParserElement}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return other ^ self\r
+\r
+    def __and__(self, other ):\r
+        """\r
+        Implementation of & operator - returns C{L{Each}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return Each( [ self, other ] )\r
+\r
+    def __rand__(self, other ):\r
+        """\r
+        Implementation of & operator when left operand is not a C{L{ParserElement}}\r
+        """\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        if not isinstance( other, ParserElement ):\r
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),\r
+                    SyntaxWarning, stacklevel=2)\r
+            return None\r
+        return other & self\r
+\r
+    def __invert__( self ):\r
+        """\r
+        Implementation of ~ operator - returns C{L{NotAny}}\r
+        """\r
+        return NotAny( self )\r
+\r
+    def __call__(self, name=None):\r
+        """\r
+        Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}.\r
+        \r
+        If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be\r
+        passed as C{True}.\r
+           \r
+        If C{name} is omitted, same as calling C{L{copy}}.\r
+\r
+        Example::\r
+            # these are equivalent\r
+            userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")\r
+            userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")             \r
+        """\r
+        if name is not None:\r
+            return self.setResultsName(name)\r
+        else:\r
+            return self.copy()\r
+\r
+    def suppress( self ):\r
+        """\r
+        Suppresses the output of this C{ParserElement}; useful to keep punctuation from\r
+        cluttering up returned output.\r
+        """\r
+        return Suppress( self )\r
+\r
+    def leaveWhitespace( self ):\r
+        """\r
+        Disables the skipping of whitespace before matching the characters in the\r
+        C{ParserElement}'s defined pattern.  This is normally only used internally by\r
+        the pyparsing module, but may be needed in some whitespace-sensitive grammars.\r
+        """\r
+        self.skipWhitespace = False\r
+        return self\r
+\r
+    def setWhitespaceChars( self, chars ):\r
+        """\r
+        Overrides the default whitespace chars\r
+        """\r
+        self.skipWhitespace = True\r
+        self.whiteChars = chars\r
+        self.copyDefaultWhiteChars = False\r
+        return self\r
+\r
+    def parseWithTabs( self ):\r
+        """\r
+        Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string.\r
+        Must be called before C{parseString} when the input grammar contains elements that\r
+        match C{<TAB>} characters.\r
+        """\r
+        self.keepTabs = True\r
+        return self\r
+\r
+    def ignore( self, other ):\r
+        """\r
+        Define expression to be ignored (e.g., comments) while doing pattern\r
+        matching; may be called repeatedly, to define multiple comment or other\r
+        ignorable patterns.\r
+        \r
+        Example::\r
+            patt = OneOrMore(Word(alphas))\r
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj']\r
+            \r
+            patt.ignore(cStyleComment)\r
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd']\r
+        """\r
+        if isinstance(other, basestring):\r
+            other = Suppress(other)\r
+\r
+        if isinstance( other, Suppress ):\r
+            if other not in self.ignoreExprs:\r
+                self.ignoreExprs.append(other)\r
+        else:\r
+            self.ignoreExprs.append( Suppress( other.copy() ) )\r
+        return self\r
+\r
+    def setDebugActions( self, startAction, successAction, exceptionAction ):\r
+        """\r
+        Enable display of debugging messages while doing pattern matching.\r
+        """\r
+        self.debugActions = (startAction or _defaultStartDebugAction,\r
+                             successAction or _defaultSuccessDebugAction,\r
+                             exceptionAction or _defaultExceptionDebugAction)\r
+        self.debug = True\r
+        return self\r
+\r
+    def setDebug( self, flag=True ):\r
+        """\r
+        Enable display of debugging messages while doing pattern matching.\r
+        Set C{flag} to True to enable, False to disable.\r
+\r
+        Example::\r
+            wd = Word(alphas).setName("alphaword")\r
+            integer = Word(nums).setName("numword")\r
+            term = wd | integer\r
+            \r
+            # turn on debugging for wd\r
+            wd.setDebug()\r
+\r
+            OneOrMore(term).parseString("abc 123 xyz 890")\r
+        \r
+        prints::\r
+            Match alphaword at loc 0(1,1)\r
+            Matched alphaword -> ['abc']\r
+            Match alphaword at loc 3(1,4)\r
+            Exception raised:Expected alphaword (at char 4), (line:1, col:5)\r
+            Match alphaword at loc 7(1,8)\r
+            Matched alphaword -> ['xyz']\r
+            Match alphaword at loc 11(1,12)\r
+            Exception raised:Expected alphaword (at char 12), (line:1, col:13)\r
+            Match alphaword at loc 15(1,16)\r
+            Exception raised:Expected alphaword (at char 15), (line:1, col:16)\r
+\r
+        The output shown is that produced by the default debug actions - custom debug actions can be\r
+        specified using L{setDebugActions}. Prior to attempting\r
+        to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"}\r
+        is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"}\r
+        message is shown. Also note the use of L{setName} to assign a human-readable name to the expression,\r
+        which makes debugging and exception messages easier to understand - for instance, the default\r
+        name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}.\r
+        """\r
+        if flag:\r
+            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )\r
+        else:\r
+            self.debug = False\r
+        return self\r
+\r
+    def __str__( self ):\r
+        return self.name\r
+\r
+    def __repr__( self ):\r
+        return _ustr(self)\r
+\r
+    def streamline( self ):\r
+        self.streamlined = True\r
+        self.strRepr = None\r
+        return self\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        pass\r
+\r
+    def validate( self, validateTrace=[] ):\r
+        """\r
+        Check defined expressions for valid structure, check for infinite recursive definitions.\r
+        """\r
+        self.checkRecursion( [] )\r
+\r
+    def parseFile( self, file_or_filename, parseAll=False ):\r
+        """\r
+        Execute the parse expression on the given file or filename.\r
+        If a filename is specified (instead of a file object),\r
+        the entire file is opened, read, and closed before parsing.\r
+        """\r
+        try:\r
+            file_contents = file_or_filename.read()\r
+        except AttributeError:\r
+            with open(file_or_filename, "r") as f:\r
+                file_contents = f.read()\r
+        try:\r
+            return self.parseString(file_contents, parseAll)\r
+        except ParseBaseException as exc:\r
+            if ParserElement.verbose_stacktrace:\r
+                raise\r
+            else:\r
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace\r
+                raise exc\r
+\r
+    def __eq__(self,other):\r
+        if isinstance(other, ParserElement):\r
+            return self is other or vars(self) == vars(other)\r
+        elif isinstance(other, basestring):\r
+            return self.matches(other)\r
+        else:\r
+            return super(ParserElement,self)==other\r
+\r
+    def __ne__(self,other):\r
+        return not (self == other)\r
+\r
+    def __hash__(self):\r
+        return hash(id(self))\r
+\r
+    def __req__(self,other):\r
+        return self == other\r
+\r
+    def __rne__(self,other):\r
+        return not (self == other)\r
+\r
+    def matches(self, testString, parseAll=True):\r
+        """\r
+        Method for quick testing of a parser against a test string. Good for simple \r
+        inline microtests of sub expressions while building up larger parser.\r
+           \r
+        Parameters:\r
+         - testString - to test against this expression for a match\r
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests\r
+            \r
+        Example::\r
+            expr = Word(nums)\r
+            assert expr.matches("100")\r
+        """\r
+        try:\r
+            self.parseString(_ustr(testString), parseAll=parseAll)\r
+            return True\r
+        except ParseBaseException:\r
+            return False\r
+                \r
+    def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False):\r
+        """\r
+        Execute the parse expression on a series of test strings, showing each\r
+        test, the parsed results or where the parse failed. Quick and easy way to\r
+        run a parse expression against a list of sample strings.\r
+           \r
+        Parameters:\r
+         - tests - a list of separate test strings, or a multiline string of test strings\r
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests           \r
+         - comment - (default=C{'#'}) - expression for indicating embedded comments in the test \r
+              string; pass None to disable comment filtering\r
+         - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline;\r
+              if False, only dump nested list\r
+         - printResults - (default=C{True}) prints test output to stdout\r
+         - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing\r
+\r
+        Returns: a (success, results) tuple, where success indicates that all tests succeeded\r
+        (or failed if C{failureTests} is True), and the results contain a list of lines of each \r
+        test's output\r
+        \r
+        Example::\r
+            number_expr = pyparsing_common.number.copy()\r
+\r
+            result = number_expr.runTests('''\r
+                # unsigned integer\r
+                100\r
+                # negative integer\r
+                -100\r
+                # float with scientific notation\r
+                6.02e23\r
+                # integer with scientific notation\r
+                1e-12\r
+                ''')\r
+            print("Success" if result[0] else "Failed!")\r
+\r
+            result = number_expr.runTests('''\r
+                # stray character\r
+                100Z\r
+                # missing leading digit before '.'\r
+                -.100\r
+                # too many '.'\r
+                3.14.159\r
+                ''', failureTests=True)\r
+            print("Success" if result[0] else "Failed!")\r
+        prints::\r
+            # unsigned integer\r
+            100\r
+            [100]\r
+\r
+            # negative integer\r
+            -100\r
+            [-100]\r
+\r
+            # float with scientific notation\r
+            6.02e23\r
+            [6.02e+23]\r
+\r
+            # integer with scientific notation\r
+            1e-12\r
+            [1e-12]\r
+\r
+            Success\r
+            \r
+            # stray character\r
+            100Z\r
+               ^\r
+            FAIL: Expected end of text (at char 3), (line:1, col:4)\r
+\r
+            # missing leading digit before '.'\r
+            -.100\r
+            ^\r
+            FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1)\r
+\r
+            # too many '.'\r
+            3.14.159\r
+                ^\r
+            FAIL: Expected end of text (at char 4), (line:1, col:5)\r
+\r
+            Success\r
+\r
+        Each test string must be on a single line. If you want to test a string that spans multiple\r
+        lines, create a test like this::\r
+\r
+            expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines")\r
+        \r
+        (Note that this is a raw string literal, you must include the leading 'r'.)\r
+        """\r
+        if isinstance(tests, basestring):\r
+            tests = list(map(str.strip, tests.rstrip().splitlines()))\r
+        if isinstance(comment, basestring):\r
+            comment = Literal(comment)\r
+        allResults = []\r
+        comments = []\r
+        success = True\r
+        for t in tests:\r
+            if comment is not None and comment.matches(t, False) or comments and not t:\r
+                comments.append(t)\r
+                continue\r
+            if not t:\r
+                continue\r
+            out = ['\n'.join(comments), t]\r
+            comments = []\r
+            try:\r
+                t = t.replace(r'\n','\n')\r
+                result = self.parseString(t, parseAll=parseAll)\r
+                out.append(result.dump(full=fullDump))\r
+                success = success and not failureTests\r
+            except ParseBaseException as pe:\r
+                fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""\r
+                if '\n' in t:\r
+                    out.append(line(pe.loc, t))\r
+                    out.append(' '*(col(pe.loc,t)-1) + '^' + fatal)\r
+                else:\r
+                    out.append(' '*pe.loc + '^' + fatal)\r
+                out.append("FAIL: " + str(pe))\r
+                success = success and failureTests\r
+                result = pe\r
+            except Exception as exc:\r
+                out.append("FAIL-EXCEPTION: " + str(exc))\r
+                success = success and failureTests\r
+                result = exc\r
+\r
+            if printResults:\r
+                if fullDump:\r
+                    out.append('')\r
+                print('\n'.join(out))\r
+\r
+            allResults.append((t, result))\r
+        \r
+        return success, allResults\r
+\r
+        \r
+class Token(ParserElement):\r
+    """\r
+    Abstract C{ParserElement} subclass, for defining atomic matching patterns.\r
+    """\r
+    def __init__( self ):\r
+        super(Token,self).__init__( savelist=False )\r
+\r
+\r
+class Empty(Token):\r
+    """\r
+    An empty token, will always match.\r
+    """\r
+    def __init__( self ):\r
+        super(Empty,self).__init__()\r
+        self.name = "Empty"\r
+        self.mayReturnEmpty = True\r
+        self.mayIndexError = False\r
+\r
+\r
+class NoMatch(Token):\r
+    """\r
+    A token that will never match.\r
+    """\r
+    def __init__( self ):\r
+        super(NoMatch,self).__init__()\r
+        self.name = "NoMatch"\r
+        self.mayReturnEmpty = True\r
+        self.mayIndexError = False\r
+        self.errmsg = "Unmatchable token"\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+\r
+class Literal(Token):\r
+    """\r
+    Token to exactly match a specified string.\r
+    \r
+    Example::\r
+        Literal('blah').parseString('blah')  # -> ['blah']\r
+        Literal('blah').parseString('blahfooblah')  # -> ['blah']\r
+        Literal('blah').parseString('bla')  # -> Exception: Expected "blah"\r
+    \r
+    For case-insensitive matching, use L{CaselessLiteral}.\r
+    \r
+    For keyword matching (force word break before and after the matched string),\r
+    use L{Keyword} or L{CaselessKeyword}.\r
+    """\r
+    def __init__( self, matchString ):\r
+        super(Literal,self).__init__()\r
+        self.match = matchString\r
+        self.matchLen = len(matchString)\r
+        try:\r
+            self.firstMatchChar = matchString[0]\r
+        except IndexError:\r
+            warnings.warn("null string passed to Literal; use Empty() instead",\r
+                            SyntaxWarning, stacklevel=2)\r
+            self.__class__ = Empty\r
+        self.name = '"%s"' % _ustr(self.match)\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayReturnEmpty = False\r
+        self.mayIndexError = False\r
+\r
+    # Performance tuning: this routine gets called a *lot*\r
+    # if this is a single character match string  and the first character matches,\r
+    # short-circuit as quickly as possible, and avoid calling startswith\r
+    #~ @profile\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if (instring[loc] == self.firstMatchChar and\r
+            (self.matchLen==1 or instring.startswith(self.match,loc)) ):\r
+            return loc+self.matchLen, self.match\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+_L = Literal\r
+ParserElement._literalStringClass = Literal\r
+\r
+class Keyword(Token):\r
+    """\r
+    Token to exactly match a specified string as a keyword, that is, it must be\r
+    immediately followed by a non-keyword character.  Compare with C{L{Literal}}:\r
+     - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}.\r
+     - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}\r
+    Accepts two optional constructor arguments in addition to the keyword string:\r
+     - C{identChars} is a string of characters that would be valid identifier characters,\r
+          defaulting to all alphanumerics + "_" and "$"\r
+     - C{caseless} allows case-insensitive matching, default is C{False}.\r
+       \r
+    Example::\r
+        Keyword("start").parseString("start")  # -> ['start']\r
+        Keyword("start").parseString("starting")  # -> Exception\r
+\r
+    For case-insensitive matching, use L{CaselessKeyword}.\r
+    """\r
+    DEFAULT_KEYWORD_CHARS = alphanums+"_$"\r
+\r
+    def __init__( self, matchString, identChars=None, caseless=False ):\r
+        super(Keyword,self).__init__()\r
+        if identChars is None:\r
+            identChars = Keyword.DEFAULT_KEYWORD_CHARS\r
+        self.match = matchString\r
+        self.matchLen = len(matchString)\r
+        try:\r
+            self.firstMatchChar = matchString[0]\r
+        except IndexError:\r
+            warnings.warn("null string passed to Keyword; use Empty() instead",\r
+                            SyntaxWarning, stacklevel=2)\r
+        self.name = '"%s"' % self.match\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayReturnEmpty = False\r
+        self.mayIndexError = False\r
+        self.caseless = caseless\r
+        if caseless:\r
+            self.caselessmatch = matchString.upper()\r
+            identChars = identChars.upper()\r
+        self.identChars = set(identChars)\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if self.caseless:\r
+            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and\r
+                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and\r
+                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):\r
+                return loc+self.matchLen, self.match\r
+        else:\r
+            if (instring[loc] == self.firstMatchChar and\r
+                (self.matchLen==1 or instring.startswith(self.match,loc)) and\r
+                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and\r
+                (loc == 0 or instring[loc-1] not in self.identChars) ):\r
+                return loc+self.matchLen, self.match\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+    def copy(self):\r
+        c = super(Keyword,self).copy()\r
+        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS\r
+        return c\r
+\r
+    @staticmethod\r
+    def setDefaultKeywordChars( chars ):\r
+        """Overrides the default Keyword chars\r
+        """\r
+        Keyword.DEFAULT_KEYWORD_CHARS = chars\r
+\r
+class CaselessLiteral(Literal):\r
+    """\r
+    Token to match a specified string, ignoring case of letters.\r
+    Note: the matched results will always be in the case of the given\r
+    match string, NOT the case of the input text.\r
+\r
+    Example::\r
+        OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD']\r
+        \r
+    (Contrast with example for L{CaselessKeyword}.)\r
+    """\r
+    def __init__( self, matchString ):\r
+        super(CaselessLiteral,self).__init__( matchString.upper() )\r
+        # Preserve the defining literal.\r
+        self.returnString = matchString\r
+        self.name = "'%s'" % self.returnString\r
+        self.errmsg = "Expected " + self.name\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if instring[ loc:loc+self.matchLen ].upper() == self.match:\r
+            return loc+self.matchLen, self.returnString\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+class CaselessKeyword(Keyword):\r
+    """\r
+    Caseless version of L{Keyword}.\r
+\r
+    Example::\r
+        OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD']\r
+        \r
+    (Contrast with example for L{CaselessLiteral}.)\r
+    """\r
+    def __init__( self, matchString, identChars=None ):\r
+        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and\r
+             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):\r
+            return loc+self.matchLen, self.match\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+class CloseMatch(Token):\r
+    """\r
+    A variation on L{Literal} which matches "close" matches, that is, \r
+    strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters:\r
+     - C{match_string} - string to be matched\r
+     - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match\r
+    \r
+    The results from a successful parse will contain the matched text from the input string and the following named results:\r
+     - C{mismatches} - a list of the positions within the match_string where mismatches were found\r
+     - C{original} - the original match_string used to compare against the input string\r
+    \r
+    If C{mismatches} is an empty list, then the match was an exact match.\r
+    \r
+    Example::\r
+        patt = CloseMatch("ATCATCGAATGGA")\r
+        patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']})\r
+        patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1)\r
+\r
+        # exact match\r
+        patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']})\r
+\r
+        # close match allowing up to 2 mismatches\r
+        patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2)\r
+        patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})\r
+    """\r
+    def __init__(self, match_string, maxMismatches=1):\r
+        super(CloseMatch,self).__init__()\r
+        self.name = match_string\r
+        self.match_string = match_string\r
+        self.maxMismatches = maxMismatches\r
+        self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches)\r
+        self.mayIndexError = False\r
+        self.mayReturnEmpty = False\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        start = loc\r
+        instrlen = len(instring)\r
+        maxloc = start + len(self.match_string)\r
+\r
+        if maxloc <= instrlen:\r
+            match_string = self.match_string\r
+            match_stringloc = 0\r
+            mismatches = []\r
+            maxMismatches = self.maxMismatches\r
+\r
+            for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)):\r
+                src,mat = s_m\r
+                if src != mat:\r
+                    mismatches.append(match_stringloc)\r
+                    if len(mismatches) > maxMismatches:\r
+                        break\r
+            else:\r
+                loc = match_stringloc + 1\r
+                results = ParseResults([instring[start:loc]])\r
+                results['original'] = self.match_string\r
+                results['mismatches'] = mismatches\r
+                return loc, results\r
+\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+\r
+class Word(Token):\r
+    """\r
+    Token for matching words composed of allowed character sets.\r
+    Defined with string containing all allowed initial characters,\r
+    an optional string containing allowed body characters (if omitted,\r
+    defaults to the initial character set), and an optional minimum,\r
+    maximum, and/or exact length.  The default value for C{min} is 1 (a\r
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}\r
+    are 0, meaning no maximum or exact length restriction. An optional\r
+    C{excludeChars} parameter can list characters that might be found in \r
+    the input C{bodyChars} string; useful to define a word of all printables\r
+    except for one or two characters, for instance.\r
+    \r
+    L{srange} is useful for defining custom character set strings for defining \r
+    C{Word} expressions, using range notation from regular expression character sets.\r
+    \r
+    A common mistake is to use C{Word} to match a specific literal string, as in \r
+    C{Word("Address")}. Remember that C{Word} uses the string argument to define\r
+    I{sets} of matchable characters. This expression would match "Add", "AAA",\r
+    "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'.\r
+    To match an exact literal string, use L{Literal} or L{Keyword}.\r
+\r
+    pyparsing includes helper strings for building Words:\r
+     - L{alphas}\r
+     - L{nums}\r
+     - L{alphanums}\r
+     - L{hexnums}\r
+     - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.)\r
+     - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.)\r
+     - L{printables} (any non-whitespace character)\r
+\r
+    Example::\r
+        # a word composed of digits\r
+        integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9"))\r
+        \r
+        # a word with a leading capital, and zero or more lowercase\r
+        capital_word = Word(alphas.upper(), alphas.lower())\r
+\r
+        # hostnames are alphanumeric, with leading alpha, and '-'\r
+        hostname = Word(alphas, alphanums+'-')\r
+        \r
+        # roman numeral (not a strict parser, accepts invalid mix of characters)\r
+        roman = Word("IVXLCDM")\r
+        \r
+        # any string of non-whitespace characters, except for ','\r
+        csv_value = Word(printables, excludeChars=",")\r
+    """\r
+    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):\r
+        super(Word,self).__init__()\r
+        if excludeChars:\r
+            initChars = ''.join(c for c in initChars if c not in excludeChars)\r
+            if bodyChars:\r
+                bodyChars = ''.join(c for c in bodyChars if c not in excludeChars)\r
+        self.initCharsOrig = initChars\r
+        self.initChars = set(initChars)\r
+        if bodyChars :\r
+            self.bodyCharsOrig = bodyChars\r
+            self.bodyChars = set(bodyChars)\r
+        else:\r
+            self.bodyCharsOrig = initChars\r
+            self.bodyChars = set(initChars)\r
+\r
+        self.maxSpecified = max > 0\r
+\r
+        if min < 1:\r
+            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")\r
+\r
+        self.minLen = min\r
+\r
+        if max > 0:\r
+            self.maxLen = max\r
+        else:\r
+            self.maxLen = _MAX_INT\r
+\r
+        if exact > 0:\r
+            self.maxLen = exact\r
+            self.minLen = exact\r
+\r
+        self.name = _ustr(self)\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayIndexError = False\r
+        self.asKeyword = asKeyword\r
+\r
+        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):\r
+            if self.bodyCharsOrig == self.initCharsOrig:\r
+                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)\r
+            elif len(self.initCharsOrig) == 1:\r
+                self.reString = "%s[%s]*" % \\r
+                                      (re.escape(self.initCharsOrig),\r
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)\r
+            else:\r
+                self.reString = "[%s][%s]*" % \\r
+                                      (_escapeRegexRangeChars(self.initCharsOrig),\r
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)\r
+            if self.asKeyword:\r
+                self.reString = r"\b"+self.reString+r"\b"\r
+            try:\r
+                self.re = re.compile( self.reString )\r
+            except Exception:\r
+                self.re = None\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if self.re:\r
+            result = self.re.match(instring,loc)\r
+            if not result:\r
+                raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+            loc = result.end()\r
+            return loc, result.group()\r
+\r
+        if not(instring[ loc ] in self.initChars):\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        start = loc\r
+        loc += 1\r
+        instrlen = len(instring)\r
+        bodychars = self.bodyChars\r
+        maxloc = start + self.maxLen\r
+        maxloc = min( maxloc, instrlen )\r
+        while loc < maxloc and instring[loc] in bodychars:\r
+            loc += 1\r
+\r
+        throwException = False\r
+        if loc - start < self.minLen:\r
+            throwException = True\r
+        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:\r
+            throwException = True\r
+        if self.asKeyword:\r
+            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):\r
+                throwException = True\r
+\r
+        if throwException:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        return loc, instring[start:loc]\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(Word,self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+\r
+        if self.strRepr is None:\r
+\r
+            def charsAsStr(s):\r
+                if len(s)>4:\r
+                    return s[:4]+"..."\r
+                else:\r
+                    return s\r
+\r
+            if ( self.initCharsOrig != self.bodyCharsOrig ):\r
+                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )\r
+            else:\r
+                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)\r
+\r
+        return self.strRepr\r
+\r
+\r
+class Regex(Token):\r
+    """\r
+    Token for matching strings that match a given regular expression.\r
+    Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.\r
+    If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as \r
+    named parse results.\r
+\r
+    Example::\r
+        realnum = Regex(r"[+-]?\d+\.\d*")\r
+        date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)')\r
+        # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression\r
+        roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")\r
+    """\r
+    compiledREtype = type(re.compile("[A-Z]"))\r
+    def __init__( self, pattern, flags=0):\r
+        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""\r
+        super(Regex,self).__init__()\r
+\r
+        if isinstance(pattern, basestring):\r
+            if not pattern:\r
+                warnings.warn("null string passed to Regex; use Empty() instead",\r
+                        SyntaxWarning, stacklevel=2)\r
+\r
+            self.pattern = pattern\r
+            self.flags = flags\r
+\r
+            try:\r
+                self.re = re.compile(self.pattern, self.flags)\r
+                self.reString = self.pattern\r
+            except sre_constants.error:\r
+                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,\r
+                    SyntaxWarning, stacklevel=2)\r
+                raise\r
+\r
+        elif isinstance(pattern, Regex.compiledREtype):\r
+            self.re = pattern\r
+            self.pattern = \\r
+            self.reString = str(pattern)\r
+            self.flags = flags\r
+            \r
+        else:\r
+            raise ValueError("Regex may only be constructed with a string or a compiled RE object")\r
+\r
+        self.name = _ustr(self)\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayIndexError = False\r
+        self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        result = self.re.match(instring,loc)\r
+        if not result:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        loc = result.end()\r
+        d = result.groupdict()\r
+        ret = ParseResults(result.group())\r
+        if d:\r
+            for k in d:\r
+                ret[k] = d[k]\r
+        return loc,ret\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(Regex,self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "Re:(%s)" % repr(self.pattern)\r
+\r
+        return self.strRepr\r
+\r
+\r
+class QuotedString(Token):\r
+    r"""\r
+    Token for matching strings that are delimited by quoting characters.\r
+    \r
+    Defined with the following parameters:\r
+        - quoteChar - string of one or more characters defining the quote delimiting string\r
+        - escChar - character to escape quotes, typically backslash (default=C{None})\r
+        - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None})\r
+        - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})\r
+        - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})\r
+        - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)\r
+        - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True})\r
+\r
+    Example::\r
+        qs = QuotedString('"')\r
+        print(qs.searchString('lsjdf "This is the quote" sldjf'))\r
+        complex_qs = QuotedString('{{', endQuoteChar='}}')\r
+        print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf'))\r
+        sql_qs = QuotedString('"', escQuote='""')\r
+        print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf'))\r
+    prints::\r
+        [['This is the quote']]\r
+        [['This is the "quote"']]\r
+        [['This is the quote with "embedded" quotes']]\r
+    """\r
+    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True):\r
+        super(QuotedString,self).__init__()\r
+\r
+        # remove white space from quote chars - wont work anyway\r
+        quoteChar = quoteChar.strip()\r
+        if not quoteChar:\r
+            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)\r
+            raise SyntaxError()\r
+\r
+        if endQuoteChar is None:\r
+            endQuoteChar = quoteChar\r
+        else:\r
+            endQuoteChar = endQuoteChar.strip()\r
+            if not endQuoteChar:\r
+                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)\r
+                raise SyntaxError()\r
+\r
+        self.quoteChar = quoteChar\r
+        self.quoteCharLen = len(quoteChar)\r
+        self.firstQuoteChar = quoteChar[0]\r
+        self.endQuoteChar = endQuoteChar\r
+        self.endQuoteCharLen = len(endQuoteChar)\r
+        self.escChar = escChar\r
+        self.escQuote = escQuote\r
+        self.unquoteResults = unquoteResults\r
+        self.convertWhitespaceEscapes = convertWhitespaceEscapes\r
+\r
+        if multiline:\r
+            self.flags = re.MULTILINE | re.DOTALL\r
+            self.pattern = r'%s(?:[^%s%s]' % \\r
+                ( re.escape(self.quoteChar),\r
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),\r
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )\r
+        else:\r
+            self.flags = 0\r
+            self.pattern = r'%s(?:[^%s\n\r%s]' % \\r
+                ( re.escape(self.quoteChar),\r
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),\r
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )\r
+        if len(self.endQuoteChar) > 1:\r
+            self.pattern += (\r
+                '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]),\r
+                                               _escapeRegexRangeChars(self.endQuoteChar[i]))\r
+                                    for i in range(len(self.endQuoteChar)-1,0,-1)) + ')'\r
+                )\r
+        if escQuote:\r
+            self.pattern += (r'|(?:%s)' % re.escape(escQuote))\r
+        if escChar:\r
+            self.pattern += (r'|(?:%s.)' % re.escape(escChar))\r
+            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"\r
+        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))\r
+\r
+        try:\r
+            self.re = re.compile(self.pattern, self.flags)\r
+            self.reString = self.pattern\r
+        except sre_constants.error:\r
+            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,\r
+                SyntaxWarning, stacklevel=2)\r
+            raise\r
+\r
+        self.name = _ustr(self)\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayIndexError = False\r
+        self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None\r
+        if not result:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        loc = result.end()\r
+        ret = result.group()\r
+\r
+        if self.unquoteResults:\r
+\r
+            # strip off quotes\r
+            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]\r
+\r
+            if isinstance(ret,basestring):\r
+                # replace escaped whitespace\r
+                if '\\' in ret and self.convertWhitespaceEscapes:\r
+                    ws_map = {\r
+                        r'\t' : '\t',\r
+                        r'\n' : '\n',\r
+                        r'\f' : '\f',\r
+                        r'\r' : '\r',\r
+                    }\r
+                    for wslit,wschar in ws_map.items():\r
+                        ret = ret.replace(wslit, wschar)\r
+\r
+                # replace escaped characters\r
+                if self.escChar:\r
+                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)\r
+\r
+                # replace escaped quotes\r
+                if self.escQuote:\r
+                    ret = ret.replace(self.escQuote, self.endQuoteChar)\r
+\r
+        return loc, ret\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(QuotedString,self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)\r
+\r
+        return self.strRepr\r
+\r
+\r
+class CharsNotIn(Token):\r
+    """\r
+    Token for matching words composed of characters I{not} in a given set (will\r
+    include whitespace in matched characters if not listed in the provided exclusion set - see example).\r
+    Defined with string containing all disallowed characters, and an optional\r
+    minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a\r
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}\r
+    are 0, meaning no maximum or exact length restriction.\r
+\r
+    Example::\r
+        # define a comma-separated-value as anything that is not a ','\r
+        csv_value = CharsNotIn(',')\r
+        print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213"))\r
+    prints::\r
+        ['dkls', 'lsdkjf', 's12 34', '@!#', '213']\r
+    """\r
+    def __init__( self, notChars, min=1, max=0, exact=0 ):\r
+        super(CharsNotIn,self).__init__()\r
+        self.skipWhitespace = False\r
+        self.notChars = notChars\r
+\r
+        if min < 1:\r
+            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")\r
+\r
+        self.minLen = min\r
+\r
+        if max > 0:\r
+            self.maxLen = max\r
+        else:\r
+            self.maxLen = _MAX_INT\r
+\r
+        if exact > 0:\r
+            self.maxLen = exact\r
+            self.minLen = exact\r
+\r
+        self.name = _ustr(self)\r
+        self.errmsg = "Expected " + self.name\r
+        self.mayReturnEmpty = ( self.minLen == 0 )\r
+        self.mayIndexError = False\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if instring[loc] in self.notChars:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        start = loc\r
+        loc += 1\r
+        notchars = self.notChars\r
+        maxlen = min( start+self.maxLen, len(instring) )\r
+        while loc < maxlen and \\r
+              (instring[loc] not in notchars):\r
+            loc += 1\r
+\r
+        if loc - start < self.minLen:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        return loc, instring[start:loc]\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(CharsNotIn, self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+        if self.strRepr is None:\r
+            if len(self.notChars) > 4:\r
+                self.strRepr = "!W:(%s...)" % self.notChars[:4]\r
+            else:\r
+                self.strRepr = "!W:(%s)" % self.notChars\r
+\r
+        return self.strRepr\r
+\r
+class White(Token):\r
+    """\r
+    Special matching class for matching whitespace.  Normally, whitespace is ignored\r
+    by pyparsing grammars.  This class is included when some whitespace structures\r
+    are significant.  Define with a string containing the whitespace characters to be\r
+    matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,\r
+    as defined for the C{L{Word}} class.\r
+    """\r
+    whiteStrs = {\r
+        " " : "<SPC>",\r
+        "\t": "<TAB>",\r
+        "\n": "<LF>",\r
+        "\r": "<CR>",\r
+        "\f": "<FF>",\r
+        }\r
+    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):\r
+        super(White,self).__init__()\r
+        self.matchWhite = ws\r
+        self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) )\r
+        #~ self.leaveWhitespace()\r
+        self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite))\r
+        self.mayReturnEmpty = True\r
+        self.errmsg = "Expected " + self.name\r
+\r
+        self.minLen = min\r
+\r
+        if max > 0:\r
+            self.maxLen = max\r
+        else:\r
+            self.maxLen = _MAX_INT\r
+\r
+        if exact > 0:\r
+            self.maxLen = exact\r
+            self.minLen = exact\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if not(instring[ loc ] in self.matchWhite):\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+        start = loc\r
+        loc += 1\r
+        maxloc = start + self.maxLen\r
+        maxloc = min( maxloc, len(instring) )\r
+        while loc < maxloc and instring[loc] in self.matchWhite:\r
+            loc += 1\r
+\r
+        if loc - start < self.minLen:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        return loc, instring[start:loc]\r
+\r
+\r
+class _PositionToken(Token):\r
+    def __init__( self ):\r
+        super(_PositionToken,self).__init__()\r
+        self.name=self.__class__.__name__\r
+        self.mayReturnEmpty = True\r
+        self.mayIndexError = False\r
+\r
+class GoToColumn(_PositionToken):\r
+    """\r
+    Token to advance to a specific column of input text; useful for tabular report scraping.\r
+    """\r
+    def __init__( self, colno ):\r
+        super(GoToColumn,self).__init__()\r
+        self.col = colno\r
+\r
+    def preParse( self, instring, loc ):\r
+        if col(loc,instring) != self.col:\r
+            instrlen = len(instring)\r
+            if self.ignoreExprs:\r
+                loc = self._skipIgnorables( instring, loc )\r
+            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :\r
+                loc += 1\r
+        return loc\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        thiscol = col( loc, instring )\r
+        if thiscol > self.col:\r
+            raise ParseException( instring, loc, "Text not in expected column", self )\r
+        newloc = loc + self.col - thiscol\r
+        ret = instring[ loc: newloc ]\r
+        return newloc, ret\r
+\r
+\r
+class LineStart(_PositionToken):\r
+    """\r
+    Matches if current position is at the beginning of a line within the parse string\r
+    \r
+    Example::\r
+    \r
+        test = '''\\r
+        AAA this line\r
+        AAA and this line\r
+          AAA but not this one\r
+        B AAA and definitely not this one\r
+        '''\r
+\r
+        for t in (LineStart() + 'AAA' + restOfLine).searchString(test):\r
+            print(t)\r
+    \r
+    Prints::\r
+        ['AAA', ' this line']\r
+        ['AAA', ' and this line']    \r
+\r
+    """\r
+    def __init__( self ):\r
+        super(LineStart,self).__init__()\r
+        self.errmsg = "Expected start of line"\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if col(loc, instring) == 1:\r
+            return loc, []\r
+        raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+class LineEnd(_PositionToken):\r
+    """\r
+    Matches if current position is at the end of a line within the parse string\r
+    """\r
+    def __init__( self ):\r
+        super(LineEnd,self).__init__()\r
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )\r
+        self.errmsg = "Expected end of line"\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if loc<len(instring):\r
+            if instring[loc] == "\n":\r
+                return loc+1, "\n"\r
+            else:\r
+                raise ParseException(instring, loc, self.errmsg, self)\r
+        elif loc == len(instring):\r
+            return loc+1, []\r
+        else:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+class StringStart(_PositionToken):\r
+    """\r
+    Matches if current position is at the beginning of the parse string\r
+    """\r
+    def __init__( self ):\r
+        super(StringStart,self).__init__()\r
+        self.errmsg = "Expected start of text"\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if loc != 0:\r
+            # see if entire string up to here is just whitespace and ignoreables\r
+            if loc != self.preParse( instring, 0 ):\r
+                raise ParseException(instring, loc, self.errmsg, self)\r
+        return loc, []\r
+\r
+class StringEnd(_PositionToken):\r
+    """\r
+    Matches if current position is at the end of the parse string\r
+    """\r
+    def __init__( self ):\r
+        super(StringEnd,self).__init__()\r
+        self.errmsg = "Expected end of text"\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if loc < len(instring):\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+        elif loc == len(instring):\r
+            return loc+1, []\r
+        elif loc > len(instring):\r
+            return loc, []\r
+        else:\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+class WordStart(_PositionToken):\r
+    """\r
+    Matches if the current position is at the beginning of a Word, and\r
+    is not preceded by any character in a given set of C{wordChars}\r
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,\r
+    use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of\r
+    the string being parsed, or at the beginning of a line.\r
+    """\r
+    def __init__(self, wordChars = printables):\r
+        super(WordStart,self).__init__()\r
+        self.wordChars = set(wordChars)\r
+        self.errmsg = "Not at the start of a word"\r
+\r
+    def parseImpl(self, instring, loc, doActions=True ):\r
+        if loc != 0:\r
+            if (instring[loc-1] in self.wordChars or\r
+                instring[loc] not in self.wordChars):\r
+                raise ParseException(instring, loc, self.errmsg, self)\r
+        return loc, []\r
+\r
+class WordEnd(_PositionToken):\r
+    """\r
+    Matches if the current position is at the end of a Word, and\r
+    is not followed by any character in a given set of C{wordChars}\r
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,\r
+    use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of\r
+    the string being parsed, or at the end of a line.\r
+    """\r
+    def __init__(self, wordChars = printables):\r
+        super(WordEnd,self).__init__()\r
+        self.wordChars = set(wordChars)\r
+        self.skipWhitespace = False\r
+        self.errmsg = "Not at the end of a word"\r
+\r
+    def parseImpl(self, instring, loc, doActions=True ):\r
+        instrlen = len(instring)\r
+        if instrlen>0 and loc<instrlen:\r
+            if (instring[loc] in self.wordChars or\r
+                instring[loc-1] not in self.wordChars):\r
+                raise ParseException(instring, loc, self.errmsg, self)\r
+        return loc, []\r
+\r
+\r
+class ParseExpression(ParserElement):\r
+    """\r
+    Abstract subclass of ParserElement, for combining and post-processing parsed tokens.\r
+    """\r
+    def __init__( self, exprs, savelist = False ):\r
+        super(ParseExpression,self).__init__(savelist)\r
+        if isinstance( exprs, _generatorType ):\r
+            exprs = list(exprs)\r
+\r
+        if isinstance( exprs, basestring ):\r
+            self.exprs = [ ParserElement._literalStringClass( exprs ) ]\r
+        elif isinstance( exprs, collections.Iterable ):\r
+            exprs = list(exprs)\r
+            # if sequence of strings provided, wrap with Literal\r
+            if all(isinstance(expr, basestring) for expr in exprs):\r
+                exprs = map(ParserElement._literalStringClass, exprs)\r
+            self.exprs = list(exprs)\r
+        else:\r
+            try:\r
+                self.exprs = list( exprs )\r
+            except TypeError:\r
+                self.exprs = [ exprs ]\r
+        self.callPreparse = False\r
+\r
+    def __getitem__( self, i ):\r
+        return self.exprs[i]\r
+\r
+    def append( self, other ):\r
+        self.exprs.append( other )\r
+        self.strRepr = None\r
+        return self\r
+\r
+    def leaveWhitespace( self ):\r
+        """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on\r
+           all contained expressions."""\r
+        self.skipWhitespace = False\r
+        self.exprs = [ e.copy() for e in self.exprs ]\r
+        for e in self.exprs:\r
+            e.leaveWhitespace()\r
+        return self\r
+\r
+    def ignore( self, other ):\r
+        if isinstance( other, Suppress ):\r
+            if other not in self.ignoreExprs:\r
+                super( ParseExpression, self).ignore( other )\r
+                for e in self.exprs:\r
+                    e.ignore( self.ignoreExprs[-1] )\r
+        else:\r
+            super( ParseExpression, self).ignore( other )\r
+            for e in self.exprs:\r
+                e.ignore( self.ignoreExprs[-1] )\r
+        return self\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(ParseExpression,self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )\r
+        return self.strRepr\r
+\r
+    def streamline( self ):\r
+        super(ParseExpression,self).streamline()\r
+\r
+        for e in self.exprs:\r
+            e.streamline()\r
+\r
+        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )\r
+        # but only if there are no parse actions or resultsNames on the nested And's\r
+        # (likewise for Or's and MatchFirst's)\r
+        if ( len(self.exprs) == 2 ):\r
+            other = self.exprs[0]\r
+            if ( isinstance( other, self.__class__ ) and\r
+                  not(other.parseAction) and\r
+                  other.resultsName is None and\r
+                  not other.debug ):\r
+                self.exprs = other.exprs[:] + [ self.exprs[1] ]\r
+                self.strRepr = None\r
+                self.mayReturnEmpty |= other.mayReturnEmpty\r
+                self.mayIndexError  |= other.mayIndexError\r
+\r
+            other = self.exprs[-1]\r
+            if ( isinstance( other, self.__class__ ) and\r
+                  not(other.parseAction) and\r
+                  other.resultsName is None and\r
+                  not other.debug ):\r
+                self.exprs = self.exprs[:-1] + other.exprs[:]\r
+                self.strRepr = None\r
+                self.mayReturnEmpty |= other.mayReturnEmpty\r
+                self.mayIndexError  |= other.mayIndexError\r
+\r
+        self.errmsg = "Expected " + _ustr(self)\r
+        \r
+        return self\r
+\r
+    def setResultsName( self, name, listAllMatches=False ):\r
+        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)\r
+        return ret\r
+\r
+    def validate( self, validateTrace=[] ):\r
+        tmp = validateTrace[:]+[self]\r
+        for e in self.exprs:\r
+            e.validate(tmp)\r
+        self.checkRecursion( [] )\r
+        \r
+    def copy(self):\r
+        ret = super(ParseExpression,self).copy()\r
+        ret.exprs = [e.copy() for e in self.exprs]\r
+        return ret\r
+\r
+class And(ParseExpression):\r
+    """\r
+    Requires all given C{ParseExpression}s to be found in the given order.\r
+    Expressions may be separated by whitespace.\r
+    May be constructed using the C{'+'} operator.\r
+    May also be constructed using the C{'-'} operator, which will suppress backtracking.\r
+\r
+    Example::\r
+        integer = Word(nums)\r
+        name_expr = OneOrMore(Word(alphas))\r
+\r
+        expr = And([integer("id"),name_expr("name"),integer("age")])\r
+        # more easily written as:\r
+        expr = integer("id") + name_expr("name") + integer("age")\r
+    """\r
+\r
+    class _ErrorStop(Empty):\r
+        def __init__(self, *args, **kwargs):\r
+            super(And._ErrorStop,self).__init__(*args, **kwargs)\r
+            self.name = '-'\r
+            self.leaveWhitespace()\r
+\r
+    def __init__( self, exprs, savelist = True ):\r
+        super(And,self).__init__(exprs, savelist)\r
+        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)\r
+        self.setWhitespaceChars( self.exprs[0].whiteChars )\r
+        self.skipWhitespace = self.exprs[0].skipWhitespace\r
+        self.callPreparse = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        # pass False as last arg to _parse for first element, since we already\r
+        # pre-parsed the string as part of our And pre-parsing\r
+        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )\r
+        errorStop = False\r
+        for e in self.exprs[1:]:\r
+            if isinstance(e, And._ErrorStop):\r
+                errorStop = True\r
+                continue\r
+            if errorStop:\r
+                try:\r
+                    loc, exprtokens = e._parse( instring, loc, doActions )\r
+                except ParseSyntaxException:\r
+                    raise\r
+                except ParseBaseException as pe:\r
+                    pe.__traceback__ = None\r
+                    raise ParseSyntaxException._from_exception(pe)\r
+                except IndexError:\r
+                    raise ParseSyntaxException(instring, len(instring), self.errmsg, self)\r
+            else:\r
+                loc, exprtokens = e._parse( instring, loc, doActions )\r
+            if exprtokens or exprtokens.haskeys():\r
+                resultlist += exprtokens\r
+        return loc, resultlist\r
+\r
+    def __iadd__(self, other ):\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        return self.append( other ) #And( [ self, other ] )\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        subRecCheckList = parseElementList[:] + [ self ]\r
+        for e in self.exprs:\r
+            e.checkRecursion( subRecCheckList )\r
+            if not e.mayReturnEmpty:\r
+                break\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}"\r
+\r
+        return self.strRepr\r
+\r
+\r
+class Or(ParseExpression):\r
+    """\r
+    Requires that at least one C{ParseExpression} is found.\r
+    If two expressions match, the expression that matches the longest string will be used.\r
+    May be constructed using the C{'^'} operator.\r
+\r
+    Example::\r
+        # construct Or using '^' operator\r
+        \r
+        number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums))\r
+        print(number.searchString("123 3.1416 789"))\r
+    prints::\r
+        [['123'], ['3.1416'], ['789']]\r
+    """\r
+    def __init__( self, exprs, savelist = False ):\r
+        super(Or,self).__init__(exprs, savelist)\r
+        if self.exprs:\r
+            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)\r
+        else:\r
+            self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        maxExcLoc = -1\r
+        maxException = None\r
+        matches = []\r
+        for e in self.exprs:\r
+            try:\r
+                loc2 = e.tryParse( instring, loc )\r
+            except ParseException as err:\r
+                err.__traceback__ = None\r
+                if err.loc > maxExcLoc:\r
+                    maxException = err\r
+                    maxExcLoc = err.loc\r
+            except IndexError:\r
+                if len(instring) > maxExcLoc:\r
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)\r
+                    maxExcLoc = len(instring)\r
+            else:\r
+                # save match among all matches, to retry longest to shortest\r
+                matches.append((loc2, e))\r
+\r
+        if matches:\r
+            matches.sort(key=lambda x: -x[0])\r
+            for _,e in matches:\r
+                try:\r
+                    return e._parse( instring, loc, doActions )\r
+                except ParseException as err:\r
+                    err.__traceback__ = None\r
+                    if err.loc > maxExcLoc:\r
+                        maxException = err\r
+                        maxExcLoc = err.loc\r
+\r
+        if maxException is not None:\r
+            maxException.msg = self.errmsg\r
+            raise maxException\r
+        else:\r
+            raise ParseException(instring, loc, "no defined alternatives to match", self)\r
+\r
+\r
+    def __ixor__(self, other ):\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        return self.append( other ) #Or( [ self, other ] )\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}"\r
+\r
+        return self.strRepr\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        subRecCheckList = parseElementList[:] + [ self ]\r
+        for e in self.exprs:\r
+            e.checkRecursion( subRecCheckList )\r
+\r
+\r
+class MatchFirst(ParseExpression):\r
+    """\r
+    Requires that at least one C{ParseExpression} is found.\r
+    If two expressions match, the first one listed is the one that will match.\r
+    May be constructed using the C{'|'} operator.\r
+\r
+    Example::\r
+        # construct MatchFirst using '|' operator\r
+        \r
+        # watch the order of expressions to match\r
+        number = Word(nums) | Combine(Word(nums) + '.' + Word(nums))\r
+        print(number.searchString("123 3.1416 789")) #  Fail! -> [['123'], ['3'], ['1416'], ['789']]\r
+\r
+        # put more selective expression first\r
+        number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)\r
+        print(number.searchString("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]\r
+    """\r
+    def __init__( self, exprs, savelist = False ):\r
+        super(MatchFirst,self).__init__(exprs, savelist)\r
+        if self.exprs:\r
+            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)\r
+        else:\r
+            self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        maxExcLoc = -1\r
+        maxException = None\r
+        for e in self.exprs:\r
+            try:\r
+                ret = e._parse( instring, loc, doActions )\r
+                return ret\r
+            except ParseException as err:\r
+                if err.loc > maxExcLoc:\r
+                    maxException = err\r
+                    maxExcLoc = err.loc\r
+            except IndexError:\r
+                if len(instring) > maxExcLoc:\r
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)\r
+                    maxExcLoc = len(instring)\r
+\r
+        # only got here if no expression matched, raise exception for match that made it the furthest\r
+        else:\r
+            if maxException is not None:\r
+                maxException.msg = self.errmsg\r
+                raise maxException\r
+            else:\r
+                raise ParseException(instring, loc, "no defined alternatives to match", self)\r
+\r
+    def __ior__(self, other ):\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass( other )\r
+        return self.append( other ) #MatchFirst( [ self, other ] )\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}"\r
+\r
+        return self.strRepr\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        subRecCheckList = parseElementList[:] + [ self ]\r
+        for e in self.exprs:\r
+            e.checkRecursion( subRecCheckList )\r
+\r
+\r
+class Each(ParseExpression):\r
+    """\r
+    Requires all given C{ParseExpression}s to be found, but in any order.\r
+    Expressions may be separated by whitespace.\r
+    May be constructed using the C{'&'} operator.\r
+\r
+    Example::\r
+        color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN")\r
+        shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON")\r
+        integer = Word(nums)\r
+        shape_attr = "shape:" + shape_type("shape")\r
+        posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn")\r
+        color_attr = "color:" + color("color")\r
+        size_attr = "size:" + integer("size")\r
+\r
+        # use Each (using operator '&') to accept attributes in any order \r
+        # (shape and posn are required, color and size are optional)\r
+        shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr)\r
+\r
+        shape_spec.runTests('''\r
+            shape: SQUARE color: BLACK posn: 100, 120\r
+            shape: CIRCLE size: 50 color: BLUE posn: 50,80\r
+            color:GREEN size:20 shape:TRIANGLE posn:20,40\r
+            '''\r
+            )\r
+    prints::\r
+        shape: SQUARE color: BLACK posn: 100, 120\r
+        ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']]\r
+        - color: BLACK\r
+        - posn: ['100', ',', '120']\r
+          - x: 100\r
+          - y: 120\r
+        - shape: SQUARE\r
+\r
+\r
+        shape: CIRCLE size: 50 color: BLUE posn: 50,80\r
+        ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']]\r
+        - color: BLUE\r
+        - posn: ['50', ',', '80']\r
+          - x: 50\r
+          - y: 80\r
+        - shape: CIRCLE\r
+        - size: 50\r
+\r
+\r
+        color: GREEN size: 20 shape: TRIANGLE posn: 20,40\r
+        ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']]\r
+        - color: GREEN\r
+        - posn: ['20', ',', '40']\r
+          - x: 20\r
+          - y: 40\r
+        - shape: TRIANGLE\r
+        - size: 20\r
+    """\r
+    def __init__( self, exprs, savelist = True ):\r
+        super(Each,self).__init__(exprs, savelist)\r
+        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)\r
+        self.skipWhitespace = True\r
+        self.initExprGroups = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if self.initExprGroups:\r
+            self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional))\r
+            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]\r
+            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)]\r
+            self.optionals = opt1 + opt2\r
+            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]\r
+            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]\r
+            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]\r
+            self.required += self.multirequired\r
+            self.initExprGroups = False\r
+        tmpLoc = loc\r
+        tmpReqd = self.required[:]\r
+        tmpOpt  = self.optionals[:]\r
+        matchOrder = []\r
+\r
+        keepMatching = True\r
+        while keepMatching:\r
+            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired\r
+            failed = []\r
+            for e in tmpExprs:\r
+                try:\r
+                    tmpLoc = e.tryParse( instring, tmpLoc )\r
+                except ParseException:\r
+                    failed.append(e)\r
+                else:\r
+                    matchOrder.append(self.opt1map.get(id(e),e))\r
+                    if e in tmpReqd:\r
+                        tmpReqd.remove(e)\r
+                    elif e in tmpOpt:\r
+                        tmpOpt.remove(e)\r
+            if len(failed) == len(tmpExprs):\r
+                keepMatching = False\r
+\r
+        if tmpReqd:\r
+            missing = ", ".join(_ustr(e) for e in tmpReqd)\r
+            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )\r
+\r
+        # add any unmatched Optionals, in case they have default values defined\r
+        matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]\r
+\r
+        resultlist = []\r
+        for e in matchOrder:\r
+            loc,results = e._parse(instring,loc,doActions)\r
+            resultlist.append(results)\r
+\r
+        finalResults = sum(resultlist, ParseResults([]))\r
+        return loc, finalResults\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}"\r
+\r
+        return self.strRepr\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        subRecCheckList = parseElementList[:] + [ self ]\r
+        for e in self.exprs:\r
+            e.checkRecursion( subRecCheckList )\r
+\r
+\r
+class ParseElementEnhance(ParserElement):\r
+    """\r
+    Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.\r
+    """\r
+    def __init__( self, expr, savelist=False ):\r
+        super(ParseElementEnhance,self).__init__(savelist)\r
+        if isinstance( expr, basestring ):\r
+            if issubclass(ParserElement._literalStringClass, Token):\r
+                expr = ParserElement._literalStringClass(expr)\r
+            else:\r
+                expr = ParserElement._literalStringClass(Literal(expr))\r
+        self.expr = expr\r
+        self.strRepr = None\r
+        if expr is not None:\r
+            self.mayIndexError = expr.mayIndexError\r
+            self.mayReturnEmpty = expr.mayReturnEmpty\r
+            self.setWhitespaceChars( expr.whiteChars )\r
+            self.skipWhitespace = expr.skipWhitespace\r
+            self.saveAsList = expr.saveAsList\r
+            self.callPreparse = expr.callPreparse\r
+            self.ignoreExprs.extend(expr.ignoreExprs)\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if self.expr is not None:\r
+            return self.expr._parse( instring, loc, doActions, callPreParse=False )\r
+        else:\r
+            raise ParseException("",loc,self.errmsg,self)\r
+\r
+    def leaveWhitespace( self ):\r
+        self.skipWhitespace = False\r
+        self.expr = self.expr.copy()\r
+        if self.expr is not None:\r
+            self.expr.leaveWhitespace()\r
+        return self\r
+\r
+    def ignore( self, other ):\r
+        if isinstance( other, Suppress ):\r
+            if other not in self.ignoreExprs:\r
+                super( ParseElementEnhance, self).ignore( other )\r
+                if self.expr is not None:\r
+                    self.expr.ignore( self.ignoreExprs[-1] )\r
+        else:\r
+            super( ParseElementEnhance, self).ignore( other )\r
+            if self.expr is not None:\r
+                self.expr.ignore( self.ignoreExprs[-1] )\r
+        return self\r
+\r
+    def streamline( self ):\r
+        super(ParseElementEnhance,self).streamline()\r
+        if self.expr is not None:\r
+            self.expr.streamline()\r
+        return self\r
+\r
+    def checkRecursion( self, parseElementList ):\r
+        if self in parseElementList:\r
+            raise RecursiveGrammarException( parseElementList+[self] )\r
+        subRecCheckList = parseElementList[:] + [ self ]\r
+        if self.expr is not None:\r
+            self.expr.checkRecursion( subRecCheckList )\r
+\r
+    def validate( self, validateTrace=[] ):\r
+        tmp = validateTrace[:]+[self]\r
+        if self.expr is not None:\r
+            self.expr.validate(tmp)\r
+        self.checkRecursion( [] )\r
+\r
+    def __str__( self ):\r
+        try:\r
+            return super(ParseElementEnhance,self).__str__()\r
+        except Exception:\r
+            pass\r
+\r
+        if self.strRepr is None and self.expr is not None:\r
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )\r
+        return self.strRepr\r
+\r
+\r
+class FollowedBy(ParseElementEnhance):\r
+    """\r
+    Lookahead matching of the given parse expression.  C{FollowedBy}\r
+    does I{not} advance the parsing position within the input string, it only\r
+    verifies that the specified parse expression matches at the current\r
+    position.  C{FollowedBy} always returns a null token list.\r
+\r
+    Example::\r
+        # use FollowedBy to match a label only if it is followed by a ':'\r
+        data_word = Word(alphas)\r
+        label = data_word + FollowedBy(':')\r
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))\r
+        \r
+        OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint()\r
+    prints::\r
+        [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]\r
+    """\r
+    def __init__( self, expr ):\r
+        super(FollowedBy,self).__init__(expr)\r
+        self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        self.expr.tryParse( instring, loc )\r
+        return loc, []\r
+\r
+\r
+class NotAny(ParseElementEnhance):\r
+    """\r
+    Lookahead to disallow matching with the given parse expression.  C{NotAny}\r
+    does I{not} advance the parsing position within the input string, it only\r
+    verifies that the specified parse expression does I{not} match at the current\r
+    position.  Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny}\r
+    always returns a null token list.  May be constructed using the '~' operator.\r
+\r
+    Example::\r
+        \r
+    """\r
+    def __init__( self, expr ):\r
+        super(NotAny,self).__init__(expr)\r
+        #~ self.leaveWhitespace()\r
+        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs\r
+        self.mayReturnEmpty = True\r
+        self.errmsg = "Found unwanted token, "+_ustr(self.expr)\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        if self.expr.canParseNext(instring, loc):\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+        return loc, []\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "~{" + _ustr(self.expr) + "}"\r
+\r
+        return self.strRepr\r
+\r
+class _MultipleMatch(ParseElementEnhance):\r
+    def __init__( self, expr, stopOn=None):\r
+        super(_MultipleMatch, self).__init__(expr)\r
+        self.saveAsList = True\r
+        ender = stopOn\r
+        if isinstance(ender, basestring):\r
+            ender = ParserElement._literalStringClass(ender)\r
+        self.not_ender = ~ender if ender is not None else None\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        self_expr_parse = self.expr._parse\r
+        self_skip_ignorables = self._skipIgnorables\r
+        check_ender = self.not_ender is not None\r
+        if check_ender:\r
+            try_not_ender = self.not_ender.tryParse\r
+        \r
+        # must be at least one (but first see if we are the stopOn sentinel;\r
+        # if so, fail)\r
+        if check_ender:\r
+            try_not_ender(instring, loc)\r
+        loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )\r
+        try:\r
+            hasIgnoreExprs = (not not self.ignoreExprs)\r
+            while 1:\r
+                if check_ender:\r
+                    try_not_ender(instring, loc)\r
+                if hasIgnoreExprs:\r
+                    preloc = self_skip_ignorables( instring, loc )\r
+                else:\r
+                    preloc = loc\r
+                loc, tmptokens = self_expr_parse( instring, preloc, doActions )\r
+                if tmptokens or tmptokens.haskeys():\r
+                    tokens += tmptokens\r
+        except (ParseException,IndexError):\r
+            pass\r
+\r
+        return loc, tokens\r
+        \r
+class OneOrMore(_MultipleMatch):\r
+    """\r
+    Repetition of one or more of the given expression.\r
+    \r
+    Parameters:\r
+     - expr - expression that must match one or more times\r
+     - stopOn - (default=C{None}) - expression for a terminating sentinel\r
+          (only required if the sentinel would ordinarily match the repetition \r
+          expression)          \r
+\r
+    Example::\r
+        data_word = Word(alphas)\r
+        label = data_word + FollowedBy(':')\r
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))\r
+\r
+        text = "shape: SQUARE posn: upper left color: BLACK"\r
+        OneOrMore(attr_expr).parseString(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]\r
+\r
+        # use stopOn attribute for OneOrMore to avoid reading label string as part of the data\r
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))\r
+        OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]\r
+        \r
+        # could also be written as\r
+        (attr_expr * (1,)).parseString(text).pprint()\r
+    """\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "{" + _ustr(self.expr) + "}..."\r
+\r
+        return self.strRepr\r
+\r
+class ZeroOrMore(_MultipleMatch):\r
+    """\r
+    Optional repetition of zero or more of the given expression.\r
+    \r
+    Parameters:\r
+     - expr - expression that must match zero or more times\r
+     - stopOn - (default=C{None}) - expression for a terminating sentinel\r
+          (only required if the sentinel would ordinarily match the repetition \r
+          expression)          \r
+\r
+    Example: similar to L{OneOrMore}\r
+    """\r
+    def __init__( self, expr, stopOn=None):\r
+        super(ZeroOrMore,self).__init__(expr, stopOn=stopOn)\r
+        self.mayReturnEmpty = True\r
+        \r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        try:\r
+            return super(ZeroOrMore, self).parseImpl(instring, loc, doActions)\r
+        except (ParseException,IndexError):\r
+            return loc, []\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "[" + _ustr(self.expr) + "]..."\r
+\r
+        return self.strRepr\r
+\r
+class _NullToken(object):\r
+    def __bool__(self):\r
+        return False\r
+    __nonzero__ = __bool__\r
+    def __str__(self):\r
+        return ""\r
+\r
+_optionalNotMatched = _NullToken()\r
+class Optional(ParseElementEnhance):\r
+    """\r
+    Optional matching of the given expression.\r
+\r
+    Parameters:\r
+     - expr - expression that must match zero or more times\r
+     - default (optional) - value to be returned if the optional expression is not found.\r
+\r
+    Example::\r
+        # US postal code can be a 5-digit zip, plus optional 4-digit qualifier\r
+        zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4)))\r
+        zip.runTests('''\r
+            # traditional ZIP code\r
+            12345\r
+            \r
+            # ZIP+4 form\r
+            12101-0001\r
+            \r
+            # invalid ZIP\r
+            98765-\r
+            ''')\r
+    prints::\r
+        # traditional ZIP code\r
+        12345\r
+        ['12345']\r
+\r
+        # ZIP+4 form\r
+        12101-0001\r
+        ['12101-0001']\r
+\r
+        # invalid ZIP\r
+        98765-\r
+             ^\r
+        FAIL: Expected end of text (at char 5), (line:1, col:6)\r
+    """\r
+    def __init__( self, expr, default=_optionalNotMatched ):\r
+        super(Optional,self).__init__( expr, savelist=False )\r
+        self.saveAsList = self.expr.saveAsList\r
+        self.defaultValue = default\r
+        self.mayReturnEmpty = True\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        try:\r
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )\r
+        except (ParseException,IndexError):\r
+            if self.defaultValue is not _optionalNotMatched:\r
+                if self.expr.resultsName:\r
+                    tokens = ParseResults([ self.defaultValue ])\r
+                    tokens[self.expr.resultsName] = self.defaultValue\r
+                else:\r
+                    tokens = [ self.defaultValue ]\r
+            else:\r
+                tokens = []\r
+        return loc, tokens\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+\r
+        if self.strRepr is None:\r
+            self.strRepr = "[" + _ustr(self.expr) + "]"\r
+\r
+        return self.strRepr\r
+\r
+class SkipTo(ParseElementEnhance):\r
+    """\r
+    Token for skipping over all undefined text until the matched expression is found.\r
+\r
+    Parameters:\r
+     - expr - target expression marking the end of the data to be skipped\r
+     - include - (default=C{False}) if True, the target expression is also parsed \r
+          (the skipped text and target expression are returned as a 2-element list).\r
+     - ignore - (default=C{None}) used to define grammars (typically quoted strings and \r
+          comments) that might contain false matches to the target expression\r
+     - failOn - (default=C{None}) define expressions that are not allowed to be \r
+          included in the skipped test; if found before the target expression is found, \r
+          the SkipTo is not a match\r
+\r
+    Example::\r
+        report = '''\r
+            Outstanding Issues Report - 1 Jan 2000\r
+\r
+               # | Severity | Description                               |  Days Open\r
+            -----+----------+-------------------------------------------+-----------\r
+             101 | Critical | Intermittent system crash                 |          6\r
+              94 | Cosmetic | Spelling error on Login ('log|n')         |         14\r
+              79 | Minor    | System slow when running too many reports |         47\r
+            '''\r
+        integer = Word(nums)\r
+        SEP = Suppress('|')\r
+        # use SkipTo to simply match everything up until the next SEP\r
+        # - ignore quoted strings, so that a '|' character inside a quoted string does not match\r
+        # - parse action will call token.strip() for each matched token, i.e., the description body\r
+        string_data = SkipTo(SEP, ignore=quotedString)\r
+        string_data.setParseAction(tokenMap(str.strip))\r
+        ticket_expr = (integer("issue_num") + SEP \r
+                      + string_data("sev") + SEP \r
+                      + string_data("desc") + SEP \r
+                      + integer("days_open"))\r
+        \r
+        for tkt in ticket_expr.searchString(report):\r
+            print tkt.dump()\r
+    prints::\r
+        ['101', 'Critical', 'Intermittent system crash', '6']\r
+        - days_open: 6\r
+        - desc: Intermittent system crash\r
+        - issue_num: 101\r
+        - sev: Critical\r
+        ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14']\r
+        - days_open: 14\r
+        - desc: Spelling error on Login ('log|n')\r
+        - issue_num: 94\r
+        - sev: Cosmetic\r
+        ['79', 'Minor', 'System slow when running too many reports', '47']\r
+        - days_open: 47\r
+        - desc: System slow when running too many reports\r
+        - issue_num: 79\r
+        - sev: Minor\r
+    """\r
+    def __init__( self, other, include=False, ignore=None, failOn=None ):\r
+        super( SkipTo, self ).__init__( other )\r
+        self.ignoreExpr = ignore\r
+        self.mayReturnEmpty = True\r
+        self.mayIndexError = False\r
+        self.includeMatch = include\r
+        self.asList = False\r
+        if isinstance(failOn, basestring):\r
+            self.failOn = ParserElement._literalStringClass(failOn)\r
+        else:\r
+            self.failOn = failOn\r
+        self.errmsg = "No match found for "+_ustr(self.expr)\r
+\r
+    def parseImpl( self, instring, loc, doActions=True ):\r
+        startloc = loc\r
+        instrlen = len(instring)\r
+        expr = self.expr\r
+        expr_parse = self.expr._parse\r
+        self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None\r
+        self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None\r
+        \r
+        tmploc = loc\r
+        while tmploc <= instrlen:\r
+            if self_failOn_canParseNext is not None:\r
+                # break if failOn expression matches\r
+                if self_failOn_canParseNext(instring, tmploc):\r
+                    break\r
+                    \r
+            if self_ignoreExpr_tryParse is not None:\r
+                # advance past ignore expressions\r
+                while 1:\r
+                    try:\r
+                        tmploc = self_ignoreExpr_tryParse(instring, tmploc)\r
+                    except ParseBaseException:\r
+                        break\r
+            \r
+            try:\r
+                expr_parse(instring, tmploc, doActions=False, callPreParse=False)\r
+            except (ParseException, IndexError):\r
+                # no match, advance loc in string\r
+                tmploc += 1\r
+            else:\r
+                # matched skipto expr, done\r
+                break\r
+\r
+        else:\r
+            # ran off the end of the input string without matching skipto expr, fail\r
+            raise ParseException(instring, loc, self.errmsg, self)\r
+\r
+        # build up return values\r
+        loc = tmploc\r
+        skiptext = instring[startloc:loc]\r
+        skipresult = ParseResults(skiptext)\r
+        \r
+        if self.includeMatch:\r
+            loc, mat = expr_parse(instring,loc,doActions,callPreParse=False)\r
+            skipresult += mat\r
+\r
+        return loc, skipresult\r
+\r
+class Forward(ParseElementEnhance):\r
+    """\r
+    Forward declaration of an expression to be defined later -\r
+    used for recursive grammars, such as algebraic infix notation.\r
+    When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.\r
+\r
+    Note: take care when assigning to C{Forward} not to overlook precedence of operators.\r
+    Specifically, '|' has a lower precedence than '<<', so that::\r
+        fwdExpr << a | b | c\r
+    will actually be evaluated as::\r
+        (fwdExpr << a) | b | c\r
+    thereby leaving b and c out as parseable alternatives.  It is recommended that you\r
+    explicitly group the values inserted into the C{Forward}::\r
+        fwdExpr << (a | b | c)\r
+    Converting to use the '<<=' operator instead will avoid this problem.\r
+\r
+    See L{ParseResults.pprint} for an example of a recursive parser created using\r
+    C{Forward}.\r
+    """\r
+    def __init__( self, other=None ):\r
+        super(Forward,self).__init__( other, savelist=False )\r
+\r
+    def __lshift__( self, other ):\r
+        if isinstance( other, basestring ):\r
+            other = ParserElement._literalStringClass(other)\r
+        self.expr = other\r
+        self.strRepr = None\r
+        self.mayIndexError = self.expr.mayIndexError\r
+        self.mayReturnEmpty = self.expr.mayReturnEmpty\r
+        self.setWhitespaceChars( self.expr.whiteChars )\r
+        self.skipWhitespace = self.expr.skipWhitespace\r
+        self.saveAsList = self.expr.saveAsList\r
+        self.ignoreExprs.extend(self.expr.ignoreExprs)\r
+        return self\r
+        \r
+    def __ilshift__(self, other):\r
+        return self << other\r
+    \r
+    def leaveWhitespace( self ):\r
+        self.skipWhitespace = False\r
+        return self\r
+\r
+    def streamline( self ):\r
+        if not self.streamlined:\r
+            self.streamlined = True\r
+            if self.expr is not None:\r
+                self.expr.streamline()\r
+        return self\r
+\r
+    def validate( self, validateTrace=[] ):\r
+        if self not in validateTrace:\r
+            tmp = validateTrace[:]+[self]\r
+            if self.expr is not None:\r
+                self.expr.validate(tmp)\r
+        self.checkRecursion([])\r
+\r
+    def __str__( self ):\r
+        if hasattr(self,"name"):\r
+            return self.name\r
+        return self.__class__.__name__ + ": ..."\r
+\r
+        # stubbed out for now - creates awful memory and perf issues\r
+        self._revertClass = self.__class__\r
+        self.__class__ = _ForwardNoRecurse\r
+        try:\r
+            if self.expr is not None:\r
+                retString = _ustr(self.expr)\r
+            else:\r
+                retString = "None"\r
+        finally:\r
+            self.__class__ = self._revertClass\r
+        return self.__class__.__name__ + ": " + retString\r
+\r
+    def copy(self):\r
+        if self.expr is not None:\r
+            return super(Forward,self).copy()\r
+        else:\r
+            ret = Forward()\r
+            ret <<= self\r
+            return ret\r
+\r
+class _ForwardNoRecurse(Forward):\r
+    def __str__( self ):\r
+        return "..."\r
+\r
+class TokenConverter(ParseElementEnhance):\r
+    """\r
+    Abstract subclass of C{ParseExpression}, for converting parsed results.\r
+    """\r
+    def __init__( self, expr, savelist=False ):\r
+        super(TokenConverter,self).__init__( expr )#, savelist )\r
+        self.saveAsList = False\r
+\r
+class Combine(TokenConverter):\r
+    """\r
+    Converter to concatenate all matching tokens to a single string.\r
+    By default, the matching patterns must also be contiguous in the input string;\r
+    this can be disabled by specifying C{'adjacent=False'} in the constructor.\r
+\r
+    Example::\r
+        real = Word(nums) + '.' + Word(nums)\r
+        print(real.parseString('3.1416')) # -> ['3', '.', '1416']\r
+        # will also erroneously match the following\r
+        print(real.parseString('3. 1416')) # -> ['3', '.', '1416']\r
+\r
+        real = Combine(Word(nums) + '.' + Word(nums))\r
+        print(real.parseString('3.1416')) # -> ['3.1416']\r
+        # no match when there are internal spaces\r
+        print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...)\r
+    """\r
+    def __init__( self, expr, joinString="", adjacent=True ):\r
+        super(Combine,self).__init__( expr )\r
+        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself\r
+        if adjacent:\r
+            self.leaveWhitespace()\r
+        self.adjacent = adjacent\r
+        self.skipWhitespace = True\r
+        self.joinString = joinString\r
+        self.callPreparse = True\r
+\r
+    def ignore( self, other ):\r
+        if self.adjacent:\r
+            ParserElement.ignore(self, other)\r
+        else:\r
+            super( Combine, self).ignore( other )\r
+        return self\r
+\r
+    def postParse( self, instring, loc, tokenlist ):\r
+        retToks = tokenlist.copy()\r
+        del retToks[:]\r
+        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)\r
+\r
+        if self.resultsName and retToks.haskeys():\r
+            return [ retToks ]\r
+        else:\r
+            return retToks\r
+\r
+class Group(TokenConverter):\r
+    """\r
+    Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions.\r
+\r
+    Example::\r
+        ident = Word(alphas)\r
+        num = Word(nums)\r
+        term = ident | num\r
+        func = ident + Optional(delimitedList(term))\r
+        print(func.parseString("fn a,b,100"))  # -> ['fn', 'a', 'b', '100']\r
+\r
+        func = ident + Group(Optional(delimitedList(term)))\r
+        print(func.parseString("fn a,b,100"))  # -> ['fn', ['a', 'b', '100']]\r
+    """\r
+    def __init__( self, expr ):\r
+        super(Group,self).__init__( expr )\r
+        self.saveAsList = True\r
+\r
+    def postParse( self, instring, loc, tokenlist ):\r
+        return [ tokenlist ]\r
+\r
+class Dict(TokenConverter):\r
+    """\r
+    Converter to return a repetitive expression as a list, but also as a dictionary.\r
+    Each element can also be referenced using the first token in the expression as its key.\r
+    Useful for tabular report scraping when the first column can be used as a item key.\r
+\r
+    Example::\r
+        data_word = Word(alphas)\r
+        label = data_word + FollowedBy(':')\r
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))\r
+\r
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"\r
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))\r
+        \r
+        # print attributes as plain groups\r
+        print(OneOrMore(attr_expr).parseString(text).dump())\r
+        \r
+        # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names\r
+        result = Dict(OneOrMore(Group(attr_expr))).parseString(text)\r
+        print(result.dump())\r
+        \r
+        # access named fields as dict entries, or output as dict\r
+        print(result['shape'])        \r
+        print(result.asDict())\r
+    prints::\r
+        ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']\r
+\r
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]\r
+        - color: light blue\r
+        - posn: upper left\r
+        - shape: SQUARE\r
+        - texture: burlap\r
+        SQUARE\r
+        {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}\r
+    See more examples at L{ParseResults} of accessing fields by results name.\r
+    """\r
+    def __init__( self, expr ):\r
+        super(Dict,self).__init__( expr )\r
+        self.saveAsList = True\r
+\r
+    def postParse( self, instring, loc, tokenlist ):\r
+        for i,tok in enumerate(tokenlist):\r
+            if len(tok) == 0:\r
+                continue\r
+            ikey = tok[0]\r
+            if isinstance(ikey,int):\r
+                ikey = _ustr(tok[0]).strip()\r
+            if len(tok)==1:\r
+                tokenlist[ikey] = _ParseResultsWithOffset("",i)\r
+            elif len(tok)==2 and not isinstance(tok[1],ParseResults):\r
+                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)\r
+            else:\r
+                dictvalue = tok.copy() #ParseResults(i)\r
+                del dictvalue[0]\r
+                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):\r
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)\r
+                else:\r
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)\r
+\r
+        if self.resultsName:\r
+            return [ tokenlist ]\r
+        else:\r
+            return tokenlist\r
+\r
+\r
+class Suppress(TokenConverter):\r
+    """\r
+    Converter for ignoring the results of a parsed expression.\r
+\r
+    Example::\r
+        source = "a, b, c,d"\r
+        wd = Word(alphas)\r
+        wd_list1 = wd + ZeroOrMore(',' + wd)\r
+        print(wd_list1.parseString(source))\r
+\r
+        # often, delimiters that are useful during parsing are just in the\r
+        # way afterward - use Suppress to keep them out of the parsed output\r
+        wd_list2 = wd + ZeroOrMore(Suppress(',') + wd)\r
+        print(wd_list2.parseString(source))\r
+    prints::\r
+        ['a', ',', 'b', ',', 'c', ',', 'd']\r
+        ['a', 'b', 'c', 'd']\r
+    (See also L{delimitedList}.)\r
+    """\r
+    def postParse( self, instring, loc, tokenlist ):\r
+        return []\r
+\r
+    def suppress( self ):\r
+        return self\r
+\r
+\r
+class OnlyOnce(object):\r
+    """\r
+    Wrapper for parse actions, to ensure they are only called once.\r
+    """\r
+    def __init__(self, methodCall):\r
+        self.callable = _trim_arity(methodCall)\r
+        self.called = False\r
+    def __call__(self,s,l,t):\r
+        if not self.called:\r
+            results = self.callable(s,l,t)\r
+            self.called = True\r
+            return results\r
+        raise ParseException(s,l,"")\r
+    def reset(self):\r
+        self.called = False\r
+\r
+def traceParseAction(f):\r
+    """\r
+    Decorator for debugging parse actions. \r
+    \r
+    When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".}\r
+    When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised.\r
+\r
+    Example::\r
+        wd = Word(alphas)\r
+\r
+        @traceParseAction\r
+        def remove_duplicate_chars(tokens):\r
+            return ''.join(sorted(set(''.join(tokens)))\r
+\r
+        wds = OneOrMore(wd).setParseAction(remove_duplicate_chars)\r
+        print(wds.parseString("slkdjs sld sldd sdlf sdljf"))\r
+    prints::\r
+        >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {}))\r
+        <<leaving remove_duplicate_chars (ret: 'dfjkls')\r
+        ['dfjkls']\r
+    """\r
+    f = _trim_arity(f)\r
+    def z(*paArgs):\r
+        thisFunc = f.__name__\r
+        s,l,t = paArgs[-3:]\r
+        if len(paArgs)>3:\r
+            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc\r
+        sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) )\r
+        try:\r
+            ret = f(*paArgs)\r
+        except Exception as exc:\r
+            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )\r
+            raise\r
+        sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) )\r
+        return ret\r
+    try:\r
+        z.__name__ = f.__name__\r
+    except AttributeError:\r
+        pass\r
+    return z\r
+\r
+#\r
+# global helpers\r
+#\r
+def delimitedList( expr, delim=",", combine=False ):\r
+    """\r
+    Helper to define a delimited list of expressions - the delimiter defaults to ','.\r
+    By default, the list elements and delimiters can have intervening whitespace, and\r
+    comments, but this can be overridden by passing C{combine=True} in the constructor.\r
+    If C{combine} is set to C{True}, the matching tokens are returned as a single token\r
+    string, with the delimiters included; otherwise, the matching tokens are returned\r
+    as a list of tokens, with the delimiters suppressed.\r
+\r
+    Example::\r
+        delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc']\r
+        delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE']\r
+    """\r
+    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."\r
+    if combine:\r
+        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)\r
+    else:\r
+        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)\r
+\r
+def countedArray( expr, intExpr=None ):\r
+    """\r
+    Helper to define a counted list of expressions.\r
+    This helper defines a pattern of the form::\r
+        integer expr expr expr...\r
+    where the leading integer tells how many expr expressions follow.\r
+    The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.\r
+    \r
+    If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value.\r
+\r
+    Example::\r
+        countedArray(Word(alphas)).parseString('2 ab cd ef')  # -> ['ab', 'cd']\r
+\r
+        # in this parser, the leading integer value is given in binary,\r
+        # '10' indicating that 2 values are in the array\r
+        binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2))\r
+        countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef')  # -> ['ab', 'cd']\r
+    """\r
+    arrayExpr = Forward()\r
+    def countFieldParseAction(s,l,t):\r
+        n = t[0]\r
+        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))\r
+        return []\r
+    if intExpr is None:\r
+        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))\r
+    else:\r
+        intExpr = intExpr.copy()\r
+    intExpr.setName("arrayLen")\r
+    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)\r
+    return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...')\r
+\r
+def _flatten(L):\r
+    ret = []\r
+    for i in L:\r
+        if isinstance(i,list):\r
+            ret.extend(_flatten(i))\r
+        else:\r
+            ret.append(i)\r
+    return ret\r
+\r
+def matchPreviousLiteral(expr):\r
+    """\r
+    Helper to define an expression that is indirectly defined from\r
+    the tokens matched in a previous expression, that is, it looks\r
+    for a 'repeat' of a previous expression.  For example::\r
+        first = Word(nums)\r
+        second = matchPreviousLiteral(first)\r
+        matchExpr = first + ":" + second\r
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches a\r
+    previous literal, will also match the leading C{"1:1"} in C{"1:10"}.\r
+    If this is not desired, use C{matchPreviousExpr}.\r
+    Do I{not} use with packrat parsing enabled.\r
+    """\r
+    rep = Forward()\r
+    def copyTokenToRepeater(s,l,t):\r
+        if t:\r
+            if len(t) == 1:\r
+                rep << t[0]\r
+            else:\r
+                # flatten t tokens\r
+                tflat = _flatten(t.asList())\r
+                rep << And(Literal(tt) for tt in tflat)\r
+        else:\r
+            rep << Empty()\r
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)\r
+    rep.setName('(prev) ' + _ustr(expr))\r
+    return rep\r
+\r
+def matchPreviousExpr(expr):\r
+    """\r
+    Helper to define an expression that is indirectly defined from\r
+    the tokens matched in a previous expression, that is, it looks\r
+    for a 'repeat' of a previous expression.  For example::\r
+        first = Word(nums)\r
+        second = matchPreviousExpr(first)\r
+        matchExpr = first + ":" + second\r
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches by\r
+    expressions, will I{not} match the leading C{"1:1"} in C{"1:10"};\r
+    the expressions are evaluated first, and then compared, so\r
+    C{"1"} is compared with C{"10"}.\r
+    Do I{not} use with packrat parsing enabled.\r
+    """\r
+    rep = Forward()\r
+    e2 = expr.copy()\r
+    rep <<= e2\r
+    def copyTokenToRepeater(s,l,t):\r
+        matchTokens = _flatten(t.asList())\r
+        def mustMatchTheseTokens(s,l,t):\r
+            theseTokens = _flatten(t.asList())\r
+            if  theseTokens != matchTokens:\r
+                raise ParseException("",0,"")\r
+        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )\r
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)\r
+    rep.setName('(prev) ' + _ustr(expr))\r
+    return rep\r
+\r
+def _escapeRegexRangeChars(s):\r
+    #~  escape these chars: ^-]\r
+    for c in r"\^-]":\r
+        s = s.replace(c,_bslash+c)\r
+    s = s.replace("\n",r"\n")\r
+    s = s.replace("\t",r"\t")\r
+    return _ustr(s)\r
+\r
+def oneOf( strs, caseless=False, useRegex=True ):\r
+    """\r
+    Helper to quickly define a set of alternative Literals, and makes sure to do\r
+    longest-first testing when there is a conflict, regardless of the input order,\r
+    but returns a C{L{MatchFirst}} for best performance.\r
+\r
+    Parameters:\r
+     - strs - a string of space-delimited literals, or a collection of string literals\r
+     - caseless - (default=C{False}) - treat all literals as caseless\r
+     - useRegex - (default=C{True}) - as an optimization, will generate a Regex\r
+          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or\r
+          if creating a C{Regex} raises an exception)\r
+\r
+    Example::\r
+        comp_oper = oneOf("< = > <= >= !=")\r
+        var = Word(alphas)\r
+        number = Word(nums)\r
+        term = var | number\r
+        comparison_expr = term + comp_oper + term\r
+        print(comparison_expr.searchString("B = 12  AA=23 B<=AA AA>12"))\r
+    prints::\r
+        [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']]\r
+    """\r
+    if caseless:\r
+        isequal = ( lambda a,b: a.upper() == b.upper() )\r
+        masks = ( lambda a,b: b.upper().startswith(a.upper()) )\r
+        parseElementClass = CaselessLiteral\r
+    else:\r
+        isequal = ( lambda a,b: a == b )\r
+        masks = ( lambda a,b: b.startswith(a) )\r
+        parseElementClass = Literal\r
+\r
+    symbols = []\r
+    if isinstance(strs,basestring):\r
+        symbols = strs.split()\r
+    elif isinstance(strs, collections.Iterable):\r
+        symbols = list(strs)\r
+    else:\r
+        warnings.warn("Invalid argument to oneOf, expected string or iterable",\r
+                SyntaxWarning, stacklevel=2)\r
+    if not symbols:\r
+        return NoMatch()\r
+\r
+    i = 0\r
+    while i < len(symbols)-1:\r
+        cur = symbols[i]\r
+        for j,other in enumerate(symbols[i+1:]):\r
+            if ( isequal(other, cur) ):\r
+                del symbols[i+j+1]\r
+                break\r
+            elif ( masks(cur, other) ):\r
+                del symbols[i+j+1]\r
+                symbols.insert(i,other)\r
+                cur = other\r
+                break\r
+        else:\r
+            i += 1\r
+\r
+    if not caseless and useRegex:\r
+        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))\r
+        try:\r
+            if len(symbols)==len("".join(symbols)):\r
+                return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols))\r
+            else:\r
+                return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols))\r
+        except Exception:\r
+            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",\r
+                    SyntaxWarning, stacklevel=2)\r
+\r
+\r
+    # last resort, just use MatchFirst\r
+    return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols))\r
+\r
+def dictOf( key, value ):\r
+    """\r
+    Helper to easily and clearly define a dictionary by specifying the respective patterns\r
+    for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens\r
+    in the proper order.  The key pattern can include delimiting markers or punctuation,\r
+    as long as they are suppressed, thereby leaving the significant key text.  The value\r
+    pattern can include named results, so that the C{Dict} results can include named token\r
+    fields.\r
+\r
+    Example::\r
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"\r
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))\r
+        print(OneOrMore(attr_expr).parseString(text).dump())\r
+        \r
+        attr_label = label\r
+        attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)\r
+\r
+        # similar to Dict, but simpler call format\r
+        result = dictOf(attr_label, attr_value).parseString(text)\r
+        print(result.dump())\r
+        print(result['shape'])\r
+        print(result.shape)  # object attribute access works too\r
+        print(result.asDict())\r
+    prints::\r
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]\r
+        - color: light blue\r
+        - posn: upper left\r
+        - shape: SQUARE\r
+        - texture: burlap\r
+        SQUARE\r
+        SQUARE\r
+        {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'}\r
+    """\r
+    return Dict( ZeroOrMore( Group ( key + value ) ) )\r
+\r
+def originalTextFor(expr, asString=True):\r
+    """\r
+    Helper to return the original, untokenized text for a given expression.  Useful to\r
+    restore the parsed fields of an HTML start tag into the raw tag text itself, or to\r
+    revert separate tokens with intervening whitespace back to the original matching\r
+    input text. By default, returns astring containing the original parsed text.  \r
+       \r
+    If the optional C{asString} argument is passed as C{False}, then the return value is a \r
+    C{L{ParseResults}} containing any results names that were originally matched, and a \r
+    single token containing the original matched text from the input string.  So if \r
+    the expression passed to C{L{originalTextFor}} contains expressions with defined\r
+    results names, you must set C{asString} to C{False} if you want to preserve those\r
+    results name values.\r
+\r
+    Example::\r
+        src = "this is test <b> bold <i>text</i> </b> normal text "\r
+        for tag in ("b","i"):\r
+            opener,closer = makeHTMLTags(tag)\r
+            patt = originalTextFor(opener + SkipTo(closer) + closer)\r
+            print(patt.searchString(src)[0])\r
+    prints::\r
+        ['<b> bold <i>text</i> </b>']\r
+        ['<i>text</i>']\r
+    """\r
+    locMarker = Empty().setParseAction(lambda s,loc,t: loc)\r
+    endlocMarker = locMarker.copy()\r
+    endlocMarker.callPreparse = False\r
+    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")\r
+    if asString:\r
+        extractText = lambda s,l,t: s[t._original_start:t._original_end]\r
+    else:\r
+        def extractText(s,l,t):\r
+            t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]]\r
+    matchExpr.setParseAction(extractText)\r
+    matchExpr.ignoreExprs = expr.ignoreExprs\r
+    return matchExpr\r
+\r
+def ungroup(expr): \r
+    """\r
+    Helper to undo pyparsing's default grouping of And expressions, even\r
+    if all but one are non-empty.\r
+    """\r
+    return TokenConverter(expr).setParseAction(lambda t:t[0])\r
+\r
+def locatedExpr(expr):\r
+    """\r
+    Helper to decorate a returned token with its starting and ending locations in the input string.\r
+    This helper adds the following results names:\r
+     - locn_start = location where matched expression begins\r
+     - locn_end = location where matched expression ends\r
+     - value = the actual parsed results\r
+\r
+    Be careful if the input text contains C{<TAB>} characters, you may want to call\r
+    C{L{ParserElement.parseWithTabs}}\r
+\r
+    Example::\r
+        wd = Word(alphas)\r
+        for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"):\r
+            print(match)\r
+    prints::\r
+        [[0, 'ljsdf', 5]]\r
+        [[8, 'lksdjjf', 15]]\r
+        [[18, 'lkkjj', 23]]\r
+    """\r
+    locator = Empty().setParseAction(lambda s,l,t: l)\r
+    return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end"))\r
+\r
+\r
+# convenience constants for positional expressions\r
+empty       = Empty().setName("empty")\r
+lineStart   = LineStart().setName("lineStart")\r
+lineEnd     = LineEnd().setName("lineEnd")\r
+stringStart = StringStart().setName("stringStart")\r
+stringEnd   = StringEnd().setName("stringEnd")\r
+\r
+_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])\r
+_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))\r
+_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))\r
+_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(printables, excludeChars=r'\]', exact=1) | Regex(r"\w", re.UNICODE)\r
+_charRange = Group(_singleChar + Suppress("-") + _singleChar)\r
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"\r
+\r
+def srange(s):\r
+    r"""\r
+    Helper to easily define string ranges for use in Word construction.  Borrows\r
+    syntax from regexp '[]' string range definitions::\r
+        srange("[0-9]")   -> "0123456789"\r
+        srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"\r
+        srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"\r
+    The input string must be enclosed in []'s, and the returned string is the expanded\r
+    character set joined into a single string.\r
+    The values enclosed in the []'s may be:\r
+     - a single character\r
+     - an escaped character with a leading backslash (such as C{\-} or C{\]})\r
+     - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) \r
+         (C{\0x##} is also supported for backwards compatibility) \r
+     - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character)\r
+     - a range of any of the above, separated by a dash (C{'a-z'}, etc.)\r
+     - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.)\r
+    """\r
+    _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1))\r
+    try:\r
+        return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body)\r
+    except Exception:\r
+        return ""\r
+\r
+def matchOnlyAtCol(n):\r
+    """\r
+    Helper method for defining parse actions that require matching at a specific\r
+    column in the input text.\r
+    """\r
+    def verifyCol(strg,locn,toks):\r
+        if col(locn,strg) != n:\r
+            raise ParseException(strg,locn,"matched token not at column %d" % n)\r
+    return verifyCol\r
+\r
+def replaceWith(replStr):\r
+    """\r
+    Helper method for common parse actions that simply return a literal value.  Especially\r
+    useful when used with C{L{transformString<ParserElement.transformString>}()}.\r
+\r
+    Example::\r
+        num = Word(nums).setParseAction(lambda toks: int(toks[0]))\r
+        na = oneOf("N/A NA").setParseAction(replaceWith(math.nan))\r
+        term = na | num\r
+        \r
+        OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234]\r
+    """\r
+    return lambda s,l,t: [replStr]\r
+\r
+def removeQuotes(s,l,t):\r
+    """\r
+    Helper parse action for removing quotation marks from parsed quoted strings.\r
+\r
+    Example::\r
+        # by default, quotation marks are included in parsed results\r
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"]\r
+\r
+        # use removeQuotes to strip quotation marks from parsed results\r
+        quotedString.setParseAction(removeQuotes)\r
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"]\r
+    """\r
+    return t[0][1:-1]\r
+\r
+def tokenMap(func, *args):\r
+    """\r
+    Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional \r
+    args are passed, they are forwarded to the given function as additional arguments after\r
+    the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the\r
+    parsed data to an integer using base 16.\r
+\r
+    Example (compare the last to example in L{ParserElement.transformString}::\r
+        hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16))\r
+        hex_ints.runTests('''\r
+            00 11 22 aa FF 0a 0d 1a\r
+            ''')\r
+        \r
+        upperword = Word(alphas).setParseAction(tokenMap(str.upper))\r
+        OneOrMore(upperword).runTests('''\r
+            my kingdom for a horse\r
+            ''')\r
+\r
+        wd = Word(alphas).setParseAction(tokenMap(str.title))\r
+        OneOrMore(wd).setParseAction(' '.join).runTests('''\r
+            now is the winter of our discontent made glorious summer by this sun of york\r
+            ''')\r
+    prints::\r
+        00 11 22 aa FF 0a 0d 1a\r
+        [0, 17, 34, 170, 255, 10, 13, 26]\r
+\r
+        my kingdom for a horse\r
+        ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE']\r
+\r
+        now is the winter of our discontent made glorious summer by this sun of york\r
+        ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']\r
+    """\r
+    def pa(s,l,t):\r
+        return [func(tokn, *args) for tokn in t]\r
+\r
+    try:\r
+        func_name = getattr(func, '__name__', \r
+                            getattr(func, '__class__').__name__)\r
+    except Exception:\r
+        func_name = str(func)\r
+    pa.__name__ = func_name\r
+\r
+    return pa\r
+\r
+upcaseTokens = tokenMap(lambda t: _ustr(t).upper())\r
+"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}"""\r
+\r
+downcaseTokens = tokenMap(lambda t: _ustr(t).lower())\r
+"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}"""\r
+    \r
+def _makeTags(tagStr, xml):\r
+    """Internal helper to construct opening and closing tag expressions, given a tag name"""\r
+    if isinstance(tagStr,basestring):\r
+        resname = tagStr\r
+        tagStr = Keyword(tagStr, caseless=not xml)\r
+    else:\r
+        resname = tagStr.name\r
+\r
+    tagAttrName = Word(alphas,alphanums+"_-:")\r
+    if (xml):\r
+        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )\r
+        openTag = Suppress("<") + tagStr("tag") + \\r
+                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \\r
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")\r
+    else:\r
+        printablesLessRAbrack = "".join(c for c in printables if c not in ">")\r
+        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)\r
+        openTag = Suppress("<") + tagStr("tag") + \\r
+                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \\r
+                Optional( Suppress("=") + tagAttrValue ) ))) + \\r
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")\r
+    closeTag = Combine(_L("</") + tagStr + ">")\r
+\r
+    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname)\r
+    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname)\r
+    openTag.tag = resname\r
+    closeTag.tag = resname\r
+    return openTag, closeTag\r
+\r
+def makeHTMLTags(tagStr):\r
+    """\r
+    Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches\r
+    tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values.\r
+\r
+    Example::\r
+        text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>'\r
+        # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple\r
+        a,a_end = makeHTMLTags("A")\r
+        link_expr = a + SkipTo(a_end)("link_text") + a_end\r
+        \r
+        for link in link_expr.searchString(text):\r
+            # attributes in the <A> tag (like "href" shown here) are also accessible as named results\r
+            print(link.link_text, '->', link.href)\r
+    prints::\r
+        pyparsing -> http://pyparsing.wikispaces.com\r
+    """\r
+    return _makeTags( tagStr, False )\r
+\r
+def makeXMLTags(tagStr):\r
+    """\r
+    Helper to construct opening and closing tag expressions for XML, given a tag name. Matches\r
+    tags only in the given upper/lower case.\r
+\r
+    Example: similar to L{makeHTMLTags}\r
+    """\r
+    return _makeTags( tagStr, True )\r
+\r
+def withAttribute(*args,**attrDict):\r
+    """\r
+    Helper to create a validating parse action to be used with start tags created\r
+    with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag\r
+    with a required attribute value, to avoid false matches on common tags such as\r
+    C{<TD>} or C{<DIV>}.\r
+\r
+    Call C{withAttribute} with a series of attribute names and values. Specify the list\r
+    of filter attributes names and values as:\r
+     - keyword arguments, as in C{(align="right")}, or\r
+     - as an explicit dict with C{**} operator, when an attribute name is also a Python\r
+          reserved word, as in C{**{"class":"Customer", "align":"right"}}\r
+     - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )\r
+    For attribute names with a namespace prefix, you must use the second form.  Attribute\r
+    names are matched insensitive to upper/lower case.\r
+       \r
+    If just testing for C{class} (with or without a namespace), use C{L{withClass}}.\r
+\r
+    To verify that the attribute exists, but without specifying a value, pass\r
+    C{withAttribute.ANY_VALUE} as the value.\r
+\r
+    Example::\r
+        html = '''\r
+            <div>\r
+            Some text\r
+            <div type="grid">1 4 0 1 0</div>\r
+            <div type="graph">1,3 2,3 1,1</div>\r
+            <div>this has no type</div>\r
+            </div>\r
+                \r
+        '''\r
+        div,div_end = makeHTMLTags("div")\r
+\r
+        # only match div tag having a type attribute with value "grid"\r
+        div_grid = div().setParseAction(withAttribute(type="grid"))\r
+        grid_expr = div_grid + SkipTo(div | div_end)("body")\r
+        for grid_header in grid_expr.searchString(html):\r
+            print(grid_header.body)\r
+        \r
+        # construct a match with any div tag having a type attribute, regardless of the value\r
+        div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE))\r
+        div_expr = div_any_type + SkipTo(div | div_end)("body")\r
+        for div_header in div_expr.searchString(html):\r
+            print(div_header.body)\r
+    prints::\r
+        1 4 0 1 0\r
+\r
+        1 4 0 1 0\r
+        1,3 2,3 1,1\r
+    """\r
+    if args:\r
+        attrs = args[:]\r
+    else:\r
+        attrs = attrDict.items()\r
+    attrs = [(k,v) for k,v in attrs]\r
+    def pa(s,l,tokens):\r
+        for attrName,attrValue in attrs:\r
+            if attrName not in tokens:\r
+                raise ParseException(s,l,"no matching attribute " + attrName)\r
+            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:\r
+                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %\r
+                                            (attrName, tokens[attrName], attrValue))\r
+    return pa\r
+withAttribute.ANY_VALUE = object()\r
+\r
+def withClass(classname, namespace=''):\r
+    """\r
+    Simplified version of C{L{withAttribute}} when matching on a div class - made\r
+    difficult because C{class} is a reserved word in Python.\r
+\r
+    Example::\r
+        html = '''\r
+            <div>\r
+            Some text\r
+            <div class="grid">1 4 0 1 0</div>\r
+            <div class="graph">1,3 2,3 1,1</div>\r
+            <div>this &lt;div&gt; has no class</div>\r
+            </div>\r
+                \r
+        '''\r
+        div,div_end = makeHTMLTags("div")\r
+        div_grid = div().setParseAction(withClass("grid"))\r
+        \r
+        grid_expr = div_grid + SkipTo(div | div_end)("body")\r
+        for grid_header in grid_expr.searchString(html):\r
+            print(grid_header.body)\r
+        \r
+        div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE))\r
+        div_expr = div_any_type + SkipTo(div | div_end)("body")\r
+        for div_header in div_expr.searchString(html):\r
+            print(div_header.body)\r
+    prints::\r
+        1 4 0 1 0\r
+\r
+        1 4 0 1 0\r
+        1,3 2,3 1,1\r
+    """\r
+    classattr = "%s:class" % namespace if namespace else "class"\r
+    return withAttribute(**{classattr : classname})        \r
+\r
+opAssoc = _Constants()\r
+opAssoc.LEFT = object()\r
+opAssoc.RIGHT = object()\r
+\r
+def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):\r
+    """\r
+    Helper method for constructing grammars of expressions made up of\r
+    operators working in a precedence hierarchy.  Operators may be unary or\r
+    binary, left- or right-associative.  Parse actions can also be attached\r
+    to operator expressions. The generated parser will also recognize the use \r
+    of parentheses to override operator precedences (see example below).\r
+    \r
+    Note: if you define a deep operator list, you may see performance issues\r
+    when using infixNotation. See L{ParserElement.enablePackrat} for a\r
+    mechanism to potentially improve your parser performance.\r
+\r
+    Parameters:\r
+     - baseExpr - expression representing the most basic element for the nested\r
+     - opList - list of tuples, one for each operator precedence level in the\r
+      expression grammar; each tuple is of the form\r
+      (opExpr, numTerms, rightLeftAssoc, parseAction), where:\r
+       - opExpr is the pyparsing expression for the operator;\r
+          may also be a string, which will be converted to a Literal;\r
+          if numTerms is 3, opExpr is a tuple of two expressions, for the\r
+          two operators separating the 3 terms\r
+       - numTerms is the number of terms for this operator (must\r
+          be 1, 2, or 3)\r
+       - rightLeftAssoc is the indicator whether the operator is\r
+          right or left associative, using the pyparsing-defined\r
+          constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.\r
+       - parseAction is the parse action to be associated with\r
+          expressions matching this operator expression (the\r
+          parse action tuple member may be omitted)\r
+     - lpar - expression for matching left-parentheses (default=C{Suppress('(')})\r
+     - rpar - expression for matching right-parentheses (default=C{Suppress(')')})\r
+\r
+    Example::\r
+        # simple example of four-function arithmetic with ints and variable names\r
+        integer = pyparsing_common.signed_integer\r
+        varname = pyparsing_common.identifier \r
+        \r
+        arith_expr = infixNotation(integer | varname,\r
+            [\r
+            ('-', 1, opAssoc.RIGHT),\r
+            (oneOf('* /'), 2, opAssoc.LEFT),\r
+            (oneOf('+ -'), 2, opAssoc.LEFT),\r
+            ])\r
+        \r
+        arith_expr.runTests('''\r
+            5+3*6\r
+            (5+3)*6\r
+            -2--11\r
+            ''', fullDump=False)\r
+    prints::\r
+        5+3*6\r
+        [[5, '+', [3, '*', 6]]]\r
+\r
+        (5+3)*6\r
+        [[[5, '+', 3], '*', 6]]\r
+\r
+        -2--11\r
+        [[['-', 2], '-', ['-', 11]]]\r
+    """\r
+    ret = Forward()\r
+    lastExpr = baseExpr | ( lpar + ret + rpar )\r
+    for i,operDef in enumerate(opList):\r
+        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]\r
+        termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr\r
+        if arity == 3:\r
+            if opExpr is None or len(opExpr) != 2:\r
+                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")\r
+            opExpr1, opExpr2 = opExpr\r
+        thisExpr = Forward().setName(termName)\r
+        if rightLeftAssoc == opAssoc.LEFT:\r
+            if arity == 1:\r
+                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )\r
+            elif arity == 2:\r
+                if opExpr is not None:\r
+                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )\r
+                else:\r
+                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )\r
+            elif arity == 3:\r
+                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \\r
+                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )\r
+            else:\r
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")\r
+        elif rightLeftAssoc == opAssoc.RIGHT:\r
+            if arity == 1:\r
+                # try to avoid LR with this extra test\r
+                if not isinstance(opExpr, Optional):\r
+                    opExpr = Optional(opExpr)\r
+                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )\r
+            elif arity == 2:\r
+                if opExpr is not None:\r
+                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )\r
+                else:\r
+                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )\r
+            elif arity == 3:\r
+                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \\r
+                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )\r
+            else:\r
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")\r
+        else:\r
+            raise ValueError("operator must indicate right or left associativity")\r
+        if pa:\r
+            matchExpr.setParseAction( pa )\r
+        thisExpr <<= ( matchExpr.setName(termName) | lastExpr )\r
+        lastExpr = thisExpr\r
+    ret <<= lastExpr\r
+    return ret\r
+\r
+operatorPrecedence = infixNotation\r
+"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release."""\r
+\r
+dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes")\r
+sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes")\r
+quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'|\r
+                       Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes")\r
+unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal")\r
+\r
+def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()):\r
+    """\r
+    Helper method for defining nested lists enclosed in opening and closing\r
+    delimiters ("(" and ")" are the default).\r
+\r
+    Parameters:\r
+     - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression\r
+     - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression\r
+     - content - expression for items within the nested lists (default=C{None})\r
+     - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString})\r
+\r
+    If an expression is not provided for the content argument, the nested\r
+    expression will capture all whitespace-delimited content between delimiters\r
+    as a list of separate values.\r
+\r
+    Use the C{ignoreExpr} argument to define expressions that may contain\r
+    opening or closing characters that should not be treated as opening\r
+    or closing characters for nesting, such as quotedString or a comment\r
+    expression.  Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}.\r
+    The default is L{quotedString}, but if no expressions are to be ignored,\r
+    then pass C{None} for this argument.\r
+\r
+    Example::\r
+        data_type = oneOf("void int short long char float double")\r
+        decl_data_type = Combine(data_type + Optional(Word('*')))\r
+        ident = Word(alphas+'_', alphanums+'_')\r
+        number = pyparsing_common.number\r
+        arg = Group(decl_data_type + ident)\r
+        LPAR,RPAR = map(Suppress, "()")\r
+\r
+        code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment))\r
+\r
+        c_function = (decl_data_type("type") \r
+                      + ident("name")\r
+                      + LPAR + Optional(delimitedList(arg), [])("args") + RPAR \r
+                      + code_body("body"))\r
+        c_function.ignore(cStyleComment)\r
+        \r
+        source_code = '''\r
+            int is_odd(int x) { \r
+                return (x%2); \r
+            }\r
+                \r
+            int dec_to_hex(char hchar) { \r
+                if (hchar >= '0' && hchar <= '9') { \r
+                    return (ord(hchar)-ord('0')); \r
+                } else { \r
+                    return (10+ord(hchar)-ord('A'));\r
+                } \r
+            }\r
+        '''\r
+        for func in c_function.searchString(source_code):\r
+            print("%(name)s (%(type)s) args: %(args)s" % func)\r
+\r
+    prints::\r
+        is_odd (int) args: [['int', 'x']]\r
+        dec_to_hex (int) args: [['char', 'hchar']]\r
+    """\r
+    if opener == closer:\r
+        raise ValueError("opening and closing strings cannot be the same")\r
+    if content is None:\r
+        if isinstance(opener,basestring) and isinstance(closer,basestring):\r
+            if len(opener) == 1 and len(closer)==1:\r
+                if ignoreExpr is not None:\r
+                    content = (Combine(OneOrMore(~ignoreExpr +\r
+                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))\r
+                                ).setParseAction(lambda t:t[0].strip()))\r
+                else:\r
+                    content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS\r
+                                ).setParseAction(lambda t:t[0].strip()))\r
+            else:\r
+                if ignoreExpr is not None:\r
+                    content = (Combine(OneOrMore(~ignoreExpr + \r
+                                    ~Literal(opener) + ~Literal(closer) +\r
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))\r
+                                ).setParseAction(lambda t:t[0].strip()))\r
+                else:\r
+                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +\r
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))\r
+                                ).setParseAction(lambda t:t[0].strip()))\r
+        else:\r
+            raise ValueError("opening and closing arguments must be strings if no content expression is given")\r
+    ret = Forward()\r
+    if ignoreExpr is not None:\r
+        ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )\r
+    else:\r
+        ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )\r
+    ret.setName('nested %s%s expression' % (opener,closer))\r
+    return ret\r
+\r
+def indentedBlock(blockStatementExpr, indentStack, indent=True):\r
+    """\r
+    Helper method for defining space-delimited indentation blocks, such as\r
+    those used to define block statements in Python source code.\r
+\r
+    Parameters:\r
+     - blockStatementExpr - expression defining syntax of statement that\r
+            is repeated within the indented block\r
+     - indentStack - list created by caller to manage indentation stack\r
+            (multiple statementWithIndentedBlock expressions within a single grammar\r
+            should share a common indentStack)\r
+     - indent - boolean indicating whether block must be indented beyond the\r
+            the current level; set to False for block of left-most statements\r
+            (default=C{True})\r
+\r
+    A valid block must contain at least one C{blockStatement}.\r
+\r
+    Example::\r
+        data = '''\r
+        def A(z):\r
+          A1\r
+          B = 100\r
+          G = A2\r
+          A2\r
+          A3\r
+        B\r
+        def BB(a,b,c):\r
+          BB1\r
+          def BBA():\r
+            bba1\r
+            bba2\r
+            bba3\r
+        C\r
+        D\r
+        def spam(x,y):\r
+             def eggs(z):\r
+                 pass\r
+        '''\r
+\r
+\r
+        indentStack = [1]\r
+        stmt = Forward()\r
+\r
+        identifier = Word(alphas, alphanums)\r
+        funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")\r
+        func_body = indentedBlock(stmt, indentStack)\r
+        funcDef = Group( funcDecl + func_body )\r
+\r
+        rvalue = Forward()\r
+        funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")")\r
+        rvalue << (funcCall | identifier | Word(nums))\r
+        assignment = Group(identifier + "=" + rvalue)\r
+        stmt << ( funcDef | assignment | identifier )\r
+\r
+        module_body = OneOrMore(stmt)\r
+\r
+        parseTree = module_body.parseString(data)\r
+        parseTree.pprint()\r
+    prints::\r
+        [['def',\r
+          'A',\r
+          ['(', 'z', ')'],\r
+          ':',\r
+          [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]],\r
+         'B',\r
+         ['def',\r
+          'BB',\r
+          ['(', 'a', 'b', 'c', ')'],\r
+          ':',\r
+          [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]],\r
+         'C',\r
+         'D',\r
+         ['def',\r
+          'spam',\r
+          ['(', 'x', 'y', ')'],\r
+          ':',\r
+          [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] \r
+    """\r
+    def checkPeerIndent(s,l,t):\r
+        if l >= len(s): return\r
+        curCol = col(l,s)\r
+        if curCol != indentStack[-1]:\r
+            if curCol > indentStack[-1]:\r
+                raise ParseFatalException(s,l,"illegal nesting")\r
+            raise ParseException(s,l,"not a peer entry")\r
+\r
+    def checkSubIndent(s,l,t):\r
+        curCol = col(l,s)\r
+        if curCol > indentStack[-1]:\r
+            indentStack.append( curCol )\r
+        else:\r
+            raise ParseException(s,l,"not a subentry")\r
+\r
+    def checkUnindent(s,l,t):\r
+        if l >= len(s): return\r
+        curCol = col(l,s)\r
+        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):\r
+            raise ParseException(s,l,"not an unindent")\r
+        indentStack.pop()\r
+\r
+    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())\r
+    INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT')\r
+    PEER   = Empty().setParseAction(checkPeerIndent).setName('')\r
+    UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT')\r
+    if indent:\r
+        smExpr = Group( Optional(NL) +\r
+            #~ FollowedBy(blockStatementExpr) +\r
+            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)\r
+    else:\r
+        smExpr = Group( Optional(NL) +\r
+            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )\r
+    blockStatementExpr.ignore(_bslash + LineEnd())\r
+    return smExpr.setName('indented block')\r
+\r
+alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")\r
+punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")\r
+\r
+anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag'))\r
+_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\''))\r
+commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity")\r
+def replaceHTMLEntity(t):\r
+    """Helper parser action to replace common HTML entities with their special characters"""\r
+    return _htmlEntityMap.get(t.entity)\r
+\r
+# it's easy to get these comment structures wrong - they're very common, so may as well make them available\r
+cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment")\r
+"Comment of the form C{/* ... */}"\r
+\r
+htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment")\r
+"Comment of the form C{<!-- ... -->}"\r
+\r
+restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line")\r
+dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment")\r
+"Comment of the form C{// ... (to end of line)}"\r
+\r
+cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment")\r
+"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}"\r
+\r
+javaStyleComment = cppStyleComment\r
+"Same as C{L{cppStyleComment}}"\r
+\r
+pythonStyleComment = Regex(r"#.*").setName("Python style comment")\r
+"Comment of the form C{# ... (to end of line)}"\r
+\r
+_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') +\r
+                                  Optional( Word(" \t") +\r
+                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")\r
+commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList")\r
+"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas.\r
+   This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}."""\r
+\r
+# some other useful expressions - using lower-case class name since we are really using this as a namespace\r
+class pyparsing_common:\r
+    """\r
+    Here are some common low-level expressions that may be useful in jump-starting parser development:\r
+     - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>})\r
+     - common L{programming identifiers<identifier>}\r
+     - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>})\r
+     - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>}\r
+     - L{UUID<uuid>}\r
+     - L{comma-separated list<comma_separated_list>}\r
+    Parse actions:\r
+     - C{L{convertToInteger}}\r
+     - C{L{convertToFloat}}\r
+     - C{L{convertToDate}}\r
+     - C{L{convertToDatetime}}\r
+     - C{L{stripHTMLTags}}\r
+     - C{L{upcaseTokens}}\r
+     - C{L{downcaseTokens}}\r
+\r
+    Example::\r
+        pyparsing_common.number.runTests('''\r
+            # any int or real number, returned as the appropriate type\r
+            100\r
+            -100\r
+            +100\r
+            3.14159\r
+            6.02e23\r
+            1e-12\r
+            ''')\r
+\r
+        pyparsing_common.fnumber.runTests('''\r
+            # any int or real number, returned as float\r
+            100\r
+            -100\r
+            +100\r
+            3.14159\r
+            6.02e23\r
+            1e-12\r
+            ''')\r
+\r
+        pyparsing_common.hex_integer.runTests('''\r
+            # hex numbers\r
+            100\r
+            FF\r
+            ''')\r
+\r
+        pyparsing_common.fraction.runTests('''\r
+            # fractions\r
+            1/2\r
+            -3/4\r
+            ''')\r
+\r
+        pyparsing_common.mixed_integer.runTests('''\r
+            # mixed fractions\r
+            1\r
+            1/2\r
+            -3/4\r
+            1-3/4\r
+            ''')\r
+\r
+        import uuid\r
+        pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID))\r
+        pyparsing_common.uuid.runTests('''\r
+            # uuid\r
+            12345678-1234-5678-1234-567812345678\r
+            ''')\r
+    prints::\r
+        # any int or real number, returned as the appropriate type\r
+        100\r
+        [100]\r
+\r
+        -100\r
+        [-100]\r
+\r
+        +100\r
+        [100]\r
+\r
+        3.14159\r
+        [3.14159]\r
+\r
+        6.02e23\r
+        [6.02e+23]\r
+\r
+        1e-12\r
+        [1e-12]\r
+\r
+        # any int or real number, returned as float\r
+        100\r
+        [100.0]\r
+\r
+        -100\r
+        [-100.0]\r
+\r
+        +100\r
+        [100.0]\r
+\r
+        3.14159\r
+        [3.14159]\r
+\r
+        6.02e23\r
+        [6.02e+23]\r
+\r
+        1e-12\r
+        [1e-12]\r
+\r
+        # hex numbers\r
+        100\r
+        [256]\r
+\r
+        FF\r
+        [255]\r
+\r
+        # fractions\r
+        1/2\r
+        [0.5]\r
+\r
+        -3/4\r
+        [-0.75]\r
+\r
+        # mixed fractions\r
+        1\r
+        [1]\r
+\r
+        1/2\r
+        [0.5]\r
+\r
+        -3/4\r
+        [-0.75]\r
+\r
+        1-3/4\r
+        [1.75]\r
+\r
+        # uuid\r
+        12345678-1234-5678-1234-567812345678\r
+        [UUID('12345678-1234-5678-1234-567812345678')]\r
+    """\r
+\r
+    convertToInteger = tokenMap(int)\r
+    """\r
+    Parse action for converting parsed integers to Python int\r
+    """\r
+\r
+    convertToFloat = tokenMap(float)\r
+    """\r
+    Parse action for converting parsed numbers to Python float\r
+    """\r
+\r
+    integer = Word(nums).setName("integer").setParseAction(convertToInteger)\r
+    """expression that parses an unsigned integer, returns an int"""\r
+\r
+    hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16))\r
+    """expression that parses a hexadecimal integer, returns an int"""\r
+\r
+    signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger)\r
+    """expression that parses an integer with optional leading sign, returns an int"""\r
+\r
+    fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction")\r
+    """fractional expression of an integer divided by an integer, returns a float"""\r
+    fraction.addParseAction(lambda t: t[0]/t[-1])\r
+\r
+    mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction")\r
+    """mixed integer of the form 'integer - fraction', with optional leading integer, returns float"""\r
+    mixed_integer.addParseAction(sum)\r
+\r
+    real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat)\r
+    """expression that parses a floating point number and returns a float"""\r
+\r
+    sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat)\r
+    """expression that parses a floating point number with optional scientific notation and returns a float"""\r
+\r
+    # streamlining this expression makes the docs nicer-looking\r
+    number = (sci_real | real | signed_integer).streamline()\r
+    """any numeric expression, returns the corresponding Python type"""\r
+\r
+    fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat)\r
+    """any int or real number, returned as float"""\r
+    \r
+    identifier = Word(alphas+'_', alphanums+'_').setName("identifier")\r
+    """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')"""\r
+    \r
+    ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address")\r
+    "IPv4 address (C{0.0.0.0 - 255.255.255.255})"\r
+\r
+    _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer")\r
+    _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address")\r
+    _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address")\r
+    _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8)\r
+    _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address")\r
+    ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address")\r
+    "IPv6 address (long, short, or mixed form)"\r
+    \r
+    mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address")\r
+    "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)"\r
+\r
+    @staticmethod\r
+    def convertToDate(fmt="%Y-%m-%d"):\r
+        """\r
+        Helper to create a parse action for converting parsed date string to Python datetime.date\r
+\r
+        Params -\r
+         - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"})\r
+\r
+        Example::\r
+            date_expr = pyparsing_common.iso8601_date.copy()\r
+            date_expr.setParseAction(pyparsing_common.convertToDate())\r
+            print(date_expr.parseString("1999-12-31"))\r
+        prints::\r
+            [datetime.date(1999, 12, 31)]\r
+        """\r
+        def cvt_fn(s,l,t):\r
+            try:\r
+                return datetime.strptime(t[0], fmt).date()\r
+            except ValueError as ve:\r
+                raise ParseException(s, l, str(ve))\r
+        return cvt_fn\r
+\r
+    @staticmethod\r
+    def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"):\r
+        """\r
+        Helper to create a parse action for converting parsed datetime string to Python datetime.datetime\r
+\r
+        Params -\r
+         - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"})\r
+\r
+        Example::\r
+            dt_expr = pyparsing_common.iso8601_datetime.copy()\r
+            dt_expr.setParseAction(pyparsing_common.convertToDatetime())\r
+            print(dt_expr.parseString("1999-12-31T23:59:59.999"))\r
+        prints::\r
+            [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)]\r
+        """\r
+        def cvt_fn(s,l,t):\r
+            try:\r
+                return datetime.strptime(t[0], fmt)\r
+            except ValueError as ve:\r
+                raise ParseException(s, l, str(ve))\r
+        return cvt_fn\r
+\r
+    iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date")\r
+    "ISO8601 date (C{yyyy-mm-dd})"\r
+\r
+    iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime")\r
+    "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}"\r
+\r
+    uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID")\r
+    "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})"\r
+\r
+    _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress()\r
+    @staticmethod\r
+    def stripHTMLTags(s, l, tokens):\r
+        """\r
+        Parse action to remove HTML tags from web page HTML source\r
+\r
+        Example::\r
+            # strip HTML links from normal text \r
+            text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>'\r
+            td,td_end = makeHTMLTags("TD")\r
+            table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end\r
+            \r
+            print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page'\r
+        """\r
+        return pyparsing_common._html_stripper.transformString(tokens[0])\r
+\r
+    _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') \r
+                                        + Optional( White(" \t") ) ) ).streamline().setName("commaItem")\r
+    comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list")\r
+    """Predefined expression of 1 or more printable words or quoted strings, separated by commas."""\r
+\r
+    upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper()))\r
+    """Parse action to convert tokens to upper case."""\r
+\r
+    downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower()))\r
+    """Parse action to convert tokens to lower case."""\r
+\r
+\r
+if __name__ == "__main__":\r
+\r
+    selectToken    = CaselessLiteral("select")\r
+    fromToken      = CaselessLiteral("from")\r
+\r
+    ident          = Word(alphas, alphanums + "_$")\r
+\r
+    columnName     = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens)\r
+    columnNameList = Group(delimitedList(columnName)).setName("columns")\r
+    columnSpec     = ('*' | columnNameList)\r
+\r
+    tableName      = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens)\r
+    tableNameList  = Group(delimitedList(tableName)).setName("tables")\r
+    \r
+    simpleSQL      = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables")\r
+\r
+    # demo runTests method, including embedded comments in test string\r
+    simpleSQL.runTests("""\r
+        # '*' as column list and dotted table name\r
+        select * from SYS.XYZZY\r
+\r
+        # caseless match on "SELECT", and casts back to "select"\r
+        SELECT * from XYZZY, ABC\r
+\r
+        # list of column names, and mixed case SELECT keyword\r
+        Select AA,BB,CC from Sys.dual\r
+\r
+        # multiple tables\r
+        Select A, B, C from Sys.dual, Table2\r
+\r
+        # invalid SELECT keyword - should fail\r
+        Xelect A, B, C from Sys.dual\r
+\r
+        # incomplete command - should fail\r
+        Select\r
+\r
+        # invalid column name - should fail\r
+        Select ^^^ frox Sys.dual\r
+\r
+        """)\r
+\r
+    pyparsing_common.number.runTests("""\r
+        100\r
+        -100\r
+        +100\r
+        3.14159\r
+        6.02e23\r
+        1e-12\r
+        """)\r
+\r
+    # any int or real number, returned as float\r
+    pyparsing_common.fnumber.runTests("""\r
+        100\r
+        -100\r
+        +100\r
+        3.14159\r
+        6.02e23\r
+        1e-12\r
+        """)\r
+\r
+    pyparsing_common.hex_integer.runTests("""\r
+        100\r
+        FF\r
+        """)\r
+\r
+    import uuid\r
+    pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID))\r
+    pyparsing_common.uuid.runTests("""\r
+        12345678-1234-5678-1234-567812345678\r
+        """)\r
diff --git a/pkg_resources/_vendor/six.py b/pkg_resources/_vendor/six.py
new file mode 100644 (file)
index 0000000..190c023
--- /dev/null
@@ -0,0 +1,868 @@
+"""Utilities for writing code that runs on Python 2 and 3"""
+
+# Copyright (c) 2010-2015 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from __future__ import absolute_import
+
+import functools
+import itertools
+import operator
+import sys
+import types
+
+__author__ = "Benjamin Peterson <benjamin@python.org>"
+__version__ = "1.10.0"
+
+
+# Useful for very coarse version differentiation.
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
+
+if PY3:
+    string_types = str,
+    integer_types = int,
+    class_types = type,
+    text_type = str
+    binary_type = bytes
+
+    MAXSIZE = sys.maxsize
+else:
+    string_types = basestring,
+    integer_types = (int, long)
+    class_types = (type, types.ClassType)
+    text_type = unicode
+    binary_type = str
+
+    if sys.platform.startswith("java"):
+        # Jython always uses 32 bits.
+        MAXSIZE = int((1 << 31) - 1)
+    else:
+        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
+        class X(object):
+
+            def __len__(self):
+                return 1 << 31
+        try:
+            len(X())
+        except OverflowError:
+            # 32-bit
+            MAXSIZE = int((1 << 31) - 1)
+        else:
+            # 64-bit
+            MAXSIZE = int((1 << 63) - 1)
+        del X
+
+
+def _add_doc(func, doc):
+    """Add documentation to a function."""
+    func.__doc__ = doc
+
+
+def _import_module(name):
+    """Import module, returning the module after the last dot."""
+    __import__(name)
+    return sys.modules[name]
+
+
+class _LazyDescr(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __get__(self, obj, tp):
+        result = self._resolve()
+        setattr(obj, self.name, result)  # Invokes __set__.
+        try:
+            # This is a bit ugly, but it avoids running this again by
+            # removing this descriptor.
+            delattr(obj.__class__, self.name)
+        except AttributeError:
+            pass
+        return result
+
+
+class MovedModule(_LazyDescr):
+
+    def __init__(self, name, old, new=None):
+        super(MovedModule, self).__init__(name)
+        if PY3:
+            if new is None:
+                new = name
+            self.mod = new
+        else:
+            self.mod = old
+
+    def _resolve(self):
+        return _import_module(self.mod)
+
+    def __getattr__(self, attr):
+        _module = self._resolve()
+        value = getattr(_module, attr)
+        setattr(self, attr, value)
+        return value
+
+
+class _LazyModule(types.ModuleType):
+
+    def __init__(self, name):
+        super(_LazyModule, self).__init__(name)
+        self.__doc__ = self.__class__.__doc__
+
+    def __dir__(self):
+        attrs = ["__doc__", "__name__"]
+        attrs += [attr.name for attr in self._moved_attributes]
+        return attrs
+
+    # Subclasses should override this
+    _moved_attributes = []
+
+
+class MovedAttribute(_LazyDescr):
+
+    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
+        super(MovedAttribute, self).__init__(name)
+        if PY3:
+            if new_mod is None:
+                new_mod = name
+            self.mod = new_mod
+            if new_attr is None:
+                if old_attr is None:
+                    new_attr = name
+                else:
+                    new_attr = old_attr
+            self.attr = new_attr
+        else:
+            self.mod = old_mod
+            if old_attr is None:
+                old_attr = name
+            self.attr = old_attr
+
+    def _resolve(self):
+        module = _import_module(self.mod)
+        return getattr(module, self.attr)
+
+
+class _SixMetaPathImporter(object):
+
+    """
+    A meta path importer to import six.moves and its submodules.
+
+    This class implements a PEP302 finder and loader. It should be compatible
+    with Python 2.5 and all existing versions of Python3
+    """
+
+    def __init__(self, six_module_name):
+        self.name = six_module_name
+        self.known_modules = {}
+
+    def _add_module(self, mod, *fullnames):
+        for fullname in fullnames:
+            self.known_modules[self.name + "." + fullname] = mod
+
+    def _get_module(self, fullname):
+        return self.known_modules[self.name + "." + fullname]
+
+    def find_module(self, fullname, path=None):
+        if fullname in self.known_modules:
+            return self
+        return None
+
+    def __get_module(self, fullname):
+        try:
+            return self.known_modules[fullname]
+        except KeyError:
+            raise ImportError("This loader does not know module " + fullname)
+
+    def load_module(self, fullname):
+        try:
+            # in case of a reload
+            return sys.modules[fullname]
+        except KeyError:
+            pass
+        mod = self.__get_module(fullname)
+        if isinstance(mod, MovedModule):
+            mod = mod._resolve()
+        else:
+            mod.__loader__ = self
+        sys.modules[fullname] = mod
+        return mod
+
+    def is_package(self, fullname):
+        """
+        Return true, if the named module is a package.
+
+        We need this method to get correct spec objects with
+        Python 3.4 (see PEP451)
+        """
+        return hasattr(self.__get_module(fullname), "__path__")
+
+    def get_code(self, fullname):
+        """Return None
+
+        Required, if is_package is implemented"""
+        self.__get_module(fullname)  # eventually raises ImportError
+        return None
+    get_source = get_code  # same as get_code
+
+_importer = _SixMetaPathImporter(__name__)
+
+
+class _MovedItems(_LazyModule):
+
+    """Lazy loading of moved objects"""
+    __path__ = []  # mark as package
+
+
+_moved_attributes = [
+    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
+    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
+    MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
+    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("intern", "__builtin__", "sys"),
+    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
+    MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
+    MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
+    MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
+    MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("UserDict", "UserDict", "collections"),
+    MovedAttribute("UserList", "UserList", "collections"),
+    MovedAttribute("UserString", "UserString", "collections"),
+    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
+    MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
+    MovedModule("builtins", "__builtin__"),
+    MovedModule("configparser", "ConfigParser"),
+    MovedModule("copyreg", "copy_reg"),
+    MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
+    MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
+    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
+    MovedModule("http_cookies", "Cookie", "http.cookies"),
+    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
+    MovedModule("html_parser", "HTMLParser", "html.parser"),
+    MovedModule("http_client", "httplib", "http.client"),
+    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
+    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
+    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
+    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
+    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
+    MovedModule("cPickle", "cPickle", "pickle"),
+    MovedModule("queue", "Queue"),
+    MovedModule("reprlib", "repr"),
+    MovedModule("socketserver", "SocketServer"),
+    MovedModule("_thread", "thread", "_thread"),
+    MovedModule("tkinter", "Tkinter"),
+    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
+    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
+    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
+    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+    MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
+    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
+    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
+    MovedModule("tkinter_colorchooser", "tkColorChooser",
+                "tkinter.colorchooser"),
+    MovedModule("tkinter_commondialog", "tkCommonDialog",
+                "tkinter.commondialog"),
+    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
+    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
+    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
+                "tkinter.simpledialog"),
+    MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
+    MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
+    MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
+    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
+    MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
+    MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
+]
+# Add windows specific modules.
+if sys.platform == "win32":
+    _moved_attributes += [
+        MovedModule("winreg", "_winreg"),
+    ]
+
+for attr in _moved_attributes:
+    setattr(_MovedItems, attr.name, attr)
+    if isinstance(attr, MovedModule):
+        _importer._add_module(attr, "moves." + attr.name)
+del attr
+
+_MovedItems._moved_attributes = _moved_attributes
+
+moves = _MovedItems(__name__ + ".moves")
+_importer._add_module(moves, "moves")
+
+
+class Module_six_moves_urllib_parse(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_parse"""
+
+
+_urllib_parse_moved_attributes = [
+    MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
+    MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
+    MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
+    MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
+    MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
+    MovedAttribute("urljoin", "urlparse", "urllib.parse"),
+    MovedAttribute("urlparse", "urlparse", "urllib.parse"),
+    MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
+    MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
+    MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
+    MovedAttribute("quote", "urllib", "urllib.parse"),
+    MovedAttribute("quote_plus", "urllib", "urllib.parse"),
+    MovedAttribute("unquote", "urllib", "urllib.parse"),
+    MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
+    MovedAttribute("urlencode", "urllib", "urllib.parse"),
+    MovedAttribute("splitquery", "urllib", "urllib.parse"),
+    MovedAttribute("splittag", "urllib", "urllib.parse"),
+    MovedAttribute("splituser", "urllib", "urllib.parse"),
+    MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_params", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_query", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
+]
+for attr in _urllib_parse_moved_attributes:
+    setattr(Module_six_moves_urllib_parse, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
+                      "moves.urllib_parse", "moves.urllib.parse")
+
+
+class Module_six_moves_urllib_error(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_error"""
+
+
+_urllib_error_moved_attributes = [
+    MovedAttribute("URLError", "urllib2", "urllib.error"),
+    MovedAttribute("HTTPError", "urllib2", "urllib.error"),
+    MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
+]
+for attr in _urllib_error_moved_attributes:
+    setattr(Module_six_moves_urllib_error, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
+                      "moves.urllib_error", "moves.urllib.error")
+
+
+class Module_six_moves_urllib_request(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_request"""
+
+
+_urllib_request_moved_attributes = [
+    MovedAttribute("urlopen", "urllib2", "urllib.request"),
+    MovedAttribute("install_opener", "urllib2", "urllib.request"),
+    MovedAttribute("build_opener", "urllib2", "urllib.request"),
+    MovedAttribute("pathname2url", "urllib", "urllib.request"),
+    MovedAttribute("url2pathname", "urllib", "urllib.request"),
+    MovedAttribute("getproxies", "urllib", "urllib.request"),
+    MovedAttribute("Request", "urllib2", "urllib.request"),
+    MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
+    MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
+    MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
+    MovedAttribute("FileHandler", "urllib2", "urllib.request"),
+    MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
+    MovedAttribute("urlretrieve", "urllib", "urllib.request"),
+    MovedAttribute("urlcleanup", "urllib", "urllib.request"),
+    MovedAttribute("URLopener", "urllib", "urllib.request"),
+    MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
+    MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
+]
+for attr in _urllib_request_moved_attributes:
+    setattr(Module_six_moves_urllib_request, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
+                      "moves.urllib_request", "moves.urllib.request")
+
+
+class Module_six_moves_urllib_response(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_response"""
+
+
+_urllib_response_moved_attributes = [
+    MovedAttribute("addbase", "urllib", "urllib.response"),
+    MovedAttribute("addclosehook", "urllib", "urllib.response"),
+    MovedAttribute("addinfo", "urllib", "urllib.response"),
+    MovedAttribute("addinfourl", "urllib", "urllib.response"),
+]
+for attr in _urllib_response_moved_attributes:
+    setattr(Module_six_moves_urllib_response, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
+                      "moves.urllib_response", "moves.urllib.response")
+
+
+class Module_six_moves_urllib_robotparser(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_robotparser"""
+
+
+_urllib_robotparser_moved_attributes = [
+    MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
+]
+for attr in _urllib_robotparser_moved_attributes:
+    setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
+                      "moves.urllib_robotparser", "moves.urllib.robotparser")
+
+
+class Module_six_moves_urllib(types.ModuleType):
+
+    """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
+    __path__ = []  # mark as package
+    parse = _importer._get_module("moves.urllib_parse")
+    error = _importer._get_module("moves.urllib_error")
+    request = _importer._get_module("moves.urllib_request")
+    response = _importer._get_module("moves.urllib_response")
+    robotparser = _importer._get_module("moves.urllib_robotparser")
+
+    def __dir__(self):
+        return ['parse', 'error', 'request', 'response', 'robotparser']
+
+_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
+                      "moves.urllib")
+
+
+def add_move(move):
+    """Add an item to six.moves."""
+    setattr(_MovedItems, move.name, move)
+
+
+def remove_move(name):
+    """Remove item from six.moves."""
+    try:
+        delattr(_MovedItems, name)
+    except AttributeError:
+        try:
+            del moves.__dict__[name]
+        except KeyError:
+            raise AttributeError("no such move, %r" % (name,))
+
+
+if PY3:
+    _meth_func = "__func__"
+    _meth_self = "__self__"
+
+    _func_closure = "__closure__"
+    _func_code = "__code__"
+    _func_defaults = "__defaults__"
+    _func_globals = "__globals__"
+else:
+    _meth_func = "im_func"
+    _meth_self = "im_self"
+
+    _func_closure = "func_closure"
+    _func_code = "func_code"
+    _func_defaults = "func_defaults"
+    _func_globals = "func_globals"
+
+
+try:
+    advance_iterator = next
+except NameError:
+    def advance_iterator(it):
+        return it.next()
+next = advance_iterator
+
+
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+if PY3:
+    def get_unbound_function(unbound):
+        return unbound
+
+    create_bound_method = types.MethodType
+
+    def create_unbound_method(func, cls):
+        return func
+
+    Iterator = object
+else:
+    def get_unbound_function(unbound):
+        return unbound.im_func
+
+    def create_bound_method(func, obj):
+        return types.MethodType(func, obj, obj.__class__)
+
+    def create_unbound_method(func, cls):
+        return types.MethodType(func, None, cls)
+
+    class Iterator(object):
+
+        def next(self):
+            return type(self).__next__(self)
+
+    callable = callable
+_add_doc(get_unbound_function,
+         """Get the function out of a possibly unbound function""")
+
+
+get_method_function = operator.attrgetter(_meth_func)
+get_method_self = operator.attrgetter(_meth_self)
+get_function_closure = operator.attrgetter(_func_closure)
+get_function_code = operator.attrgetter(_func_code)
+get_function_defaults = operator.attrgetter(_func_defaults)
+get_function_globals = operator.attrgetter(_func_globals)
+
+
+if PY3:
+    def iterkeys(d, **kw):
+        return iter(d.keys(**kw))
+
+    def itervalues(d, **kw):
+        return iter(d.values(**kw))
+
+    def iteritems(d, **kw):
+        return iter(d.items(**kw))
+
+    def iterlists(d, **kw):
+        return iter(d.lists(**kw))
+
+    viewkeys = operator.methodcaller("keys")
+
+    viewvalues = operator.methodcaller("values")
+
+    viewitems = operator.methodcaller("items")
+else:
+    def iterkeys(d, **kw):
+        return d.iterkeys(**kw)
+
+    def itervalues(d, **kw):
+        return d.itervalues(**kw)
+
+    def iteritems(d, **kw):
+        return d.iteritems(**kw)
+
+    def iterlists(d, **kw):
+        return d.iterlists(**kw)
+
+    viewkeys = operator.methodcaller("viewkeys")
+
+    viewvalues = operator.methodcaller("viewvalues")
+
+    viewitems = operator.methodcaller("viewitems")
+
+_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
+_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
+_add_doc(iteritems,
+         "Return an iterator over the (key, value) pairs of a dictionary.")
+_add_doc(iterlists,
+         "Return an iterator over the (key, [values]) pairs of a dictionary.")
+
+
+if PY3:
+    def b(s):
+        return s.encode("latin-1")
+
+    def u(s):
+        return s
+    unichr = chr
+    import struct
+    int2byte = struct.Struct(">B").pack
+    del struct
+    byte2int = operator.itemgetter(0)
+    indexbytes = operator.getitem
+    iterbytes = iter
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+    _assertCountEqual = "assertCountEqual"
+    if sys.version_info[1] <= 1:
+        _assertRaisesRegex = "assertRaisesRegexp"
+        _assertRegex = "assertRegexpMatches"
+    else:
+        _assertRaisesRegex = "assertRaisesRegex"
+        _assertRegex = "assertRegex"
+else:
+    def b(s):
+        return s
+    # Workaround for standalone backslash
+
+    def u(s):
+        return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
+    unichr = unichr
+    int2byte = chr
+
+    def byte2int(bs):
+        return ord(bs[0])
+
+    def indexbytes(buf, i):
+        return ord(buf[i])
+    iterbytes = functools.partial(itertools.imap, ord)
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+    _assertCountEqual = "assertItemsEqual"
+    _assertRaisesRegex = "assertRaisesRegexp"
+    _assertRegex = "assertRegexpMatches"
+_add_doc(b, """Byte literal""")
+_add_doc(u, """Text literal""")
+
+
+def assertCountEqual(self, *args, **kwargs):
+    return getattr(self, _assertCountEqual)(*args, **kwargs)
+
+
+def assertRaisesRegex(self, *args, **kwargs):
+    return getattr(self, _assertRaisesRegex)(*args, **kwargs)
+
+
+def assertRegex(self, *args, **kwargs):
+    return getattr(self, _assertRegex)(*args, **kwargs)
+
+
+if PY3:
+    exec_ = getattr(moves.builtins, "exec")
+
+    def reraise(tp, value, tb=None):
+        if value is None:
+            value = tp()
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+else:
+    def exec_(_code_, _globs_=None, _locs_=None):
+        """Execute code in a namespace."""
+        if _globs_ is None:
+            frame = sys._getframe(1)
+            _globs_ = frame.f_globals
+            if _locs_ is None:
+                _locs_ = frame.f_locals
+            del frame
+        elif _locs_ is None:
+            _locs_ = _globs_
+        exec("""exec _code_ in _globs_, _locs_""")
+
+    exec_("""def reraise(tp, value, tb=None):
+    raise tp, value, tb
+""")
+
+
+if sys.version_info[:2] == (3, 2):
+    exec_("""def raise_from(value, from_value):
+    if from_value is None:
+        raise value
+    raise value from from_value
+""")
+elif sys.version_info[:2] > (3, 2):
+    exec_("""def raise_from(value, from_value):
+    raise value from from_value
+""")
+else:
+    def raise_from(value, from_value):
+        raise value
+
+
+print_ = getattr(moves.builtins, "print", None)
+if print_ is None:
+    def print_(*args, **kwargs):
+        """The new-style print function for Python 2.4 and 2.5."""
+        fp = kwargs.pop("file", sys.stdout)
+        if fp is None:
+            return
+
+        def write(data):
+            if not isinstance(data, basestring):
+                data = str(data)
+            # If the file has an encoding, encode unicode with it.
+            if (isinstance(fp, file) and
+                    isinstance(data, unicode) and
+                    fp.encoding is not None):
+                errors = getattr(fp, "errors", None)
+                if errors is None:
+                    errors = "strict"
+                data = data.encode(fp.encoding, errors)
+            fp.write(data)
+        want_unicode = False
+        sep = kwargs.pop("sep", None)
+        if sep is not None:
+            if isinstance(sep, unicode):
+                want_unicode = True
+            elif not isinstance(sep, str):
+                raise TypeError("sep must be None or a string")
+        end = kwargs.pop("end", None)
+        if end is not None:
+            if isinstance(end, unicode):
+                want_unicode = True
+            elif not isinstance(end, str):
+                raise TypeError("end must be None or a string")
+        if kwargs:
+            raise TypeError("invalid keyword arguments to print()")
+        if not want_unicode:
+            for arg in args:
+                if isinstance(arg, unicode):
+                    want_unicode = True
+                    break
+        if want_unicode:
+            newline = unicode("\n")
+            space = unicode(" ")
+        else:
+            newline = "\n"
+            space = " "
+        if sep is None:
+            sep = space
+        if end is None:
+            end = newline
+        for i, arg in enumerate(args):
+            if i:
+                write(sep)
+            write(arg)
+        write(end)
+if sys.version_info[:2] < (3, 3):
+    _print = print_
+
+    def print_(*args, **kwargs):
+        fp = kwargs.get("file", sys.stdout)
+        flush = kwargs.pop("flush", False)
+        _print(*args, **kwargs)
+        if flush and fp is not None:
+            fp.flush()
+
+_add_doc(reraise, """Reraise an exception.""")
+
+if sys.version_info[0:2] < (3, 4):
+    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
+              updated=functools.WRAPPER_UPDATES):
+        def wrapper(f):
+            f = functools.wraps(wrapped, assigned, updated)(f)
+            f.__wrapped__ = wrapped
+            return f
+        return wrapper
+else:
+    wraps = functools.wraps
+
+
+def with_metaclass(meta, *bases):
+    """Create a base class with a metaclass."""
+    # This requires a bit of explanation: the basic idea is to make a dummy
+    # metaclass for one level of class instantiation that replaces itself with
+    # the actual metaclass.
+    class metaclass(meta):
+
+        def __new__(cls, name, this_bases, d):
+            return meta(name, bases, d)
+    return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+def add_metaclass(metaclass):
+    """Class decorator for creating a class with a metaclass."""
+    def wrapper(cls):
+        orig_vars = cls.__dict__.copy()
+        slots = orig_vars.get('__slots__')
+        if slots is not None:
+            if isinstance(slots, str):
+                slots = [slots]
+            for slots_var in slots:
+                orig_vars.pop(slots_var)
+        orig_vars.pop('__dict__', None)
+        orig_vars.pop('__weakref__', None)
+        return metaclass(cls.__name__, cls.__bases__, orig_vars)
+    return wrapper
+
+
+def python_2_unicode_compatible(klass):
+    """
+    A decorator that defines __unicode__ and __str__ methods under Python 2.
+    Under Python 3 it does nothing.
+
+    To support Python 2 and 3 with a single code base, define a __str__ method
+    returning text and apply this decorator to the class.
+    """
+    if PY2:
+        if '__str__' not in klass.__dict__:
+            raise ValueError("@python_2_unicode_compatible cannot be applied "
+                             "to %s because it doesn't define __str__()." %
+                             klass.__name__)
+        klass.__unicode__ = klass.__str__
+        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+    return klass
+
+
+# Complete the moves implementation.
+# This code is at the end of this module to speed up module loading.
+# Turn this module into a package.
+__path__ = []  # required for PEP 302 and PEP 451
+__package__ = __name__  # see PEP 366 @ReservedAssignment
+if globals().get("__spec__") is not None:
+    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable
+# Remove other six meta path importers, since they cause problems. This can
+# happen if six is removed from sys.modules and then reloaded. (Setuptools does
+# this for some reason.)
+if sys.meta_path:
+    for i, importer in enumerate(sys.meta_path):
+        # Here's some real nastiness: Another "instance" of the six module might
+        # be floating around. Therefore, we can't use isinstance() to check for
+        # the six meta path importer, since the other six instance will have
+        # inserted an importer with different class.
+        if (type(importer).__name__ == "_SixMetaPathImporter" and
+                importer.name == __name__):
+            del sys.meta_path[i]
+            break
+    del i, importer
+# Finally, add the importer to the meta path import hook.
+sys.meta_path.append(_importer)
diff --git a/pkg_resources/_vendor/vendored.txt b/pkg_resources/_vendor/vendored.txt
new file mode 100644 (file)
index 0000000..9a94c5b
--- /dev/null
@@ -0,0 +1,4 @@
+packaging==16.8
+pyparsing==2.1.10
+six==1.10.0
+appdirs==1.4.0
diff --git a/pkg_resources/extern/__init__.py b/pkg_resources/extern/__init__.py
new file mode 100644 (file)
index 0000000..b4156fe
--- /dev/null
@@ -0,0 +1,73 @@
+import sys
+
+
+class VendorImporter:
+    """
+    A PEP 302 meta path importer for finding optionally-vendored
+    or otherwise naturally-installed packages from root_name.
+    """
+
+    def __init__(self, root_name, vendored_names=(), vendor_pkg=None):
+        self.root_name = root_name
+        self.vendored_names = set(vendored_names)
+        self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor')
+
+    @property
+    def search_path(self):
+        """
+        Search first the vendor package then as a natural package.
+        """
+        yield self.vendor_pkg + '.'
+        yield ''
+
+    def find_module(self, fullname, path=None):
+        """
+        Return self when fullname starts with root_name and the
+        target module is one vendored through this importer.
+        """
+        root, base, target = fullname.partition(self.root_name + '.')
+        if root:
+            return
+        if not any(map(target.startswith, self.vendored_names)):
+            return
+        return self
+
+    def load_module(self, fullname):
+        """
+        Iterate over the search path to locate and load fullname.
+        """
+        root, base, target = fullname.partition(self.root_name + '.')
+        for prefix in self.search_path:
+            try:
+                extant = prefix + target
+                __import__(extant)
+                mod = sys.modules[extant]
+                sys.modules[fullname] = mod
+                # mysterious hack:
+                # Remove the reference to the extant package/module
+                # on later Python versions to cause relative imports
+                # in the vendor package to resolve the same modules
+                # as those going through this importer.
+                if sys.version_info > (3, 3):
+                    del sys.modules[extant]
+                return mod
+            except ImportError:
+                pass
+        else:
+            raise ImportError(
+                "The '{target}' package is required; "
+                "normally this is bundled with this package so if you get "
+                "this warning, consult the packager of your "
+                "distribution.".format(**locals())
+            )
+
+    def install(self):
+        """
+        Install this importer into sys.meta_path if not already present.
+        """
+        if self not in sys.meta_path:
+            sys.meta_path.append(self)
+
+
+names = 'packaging', 'pyparsing', 'six', 'appdirs'
+VendorImporter(__name__, names).install()
index bef914a..49bf7a0 100644 (file)
@@ -12,7 +12,7 @@ import stat
 import distutils.dist
 import distutils.command.install_egg_info
 
-from six.moves import map
+from pkg_resources.extern.six.moves import map
 
 import pytest
 
index b997aaa..0b05343 100644 (file)
@@ -5,10 +5,10 @@ import sys
 import string
 import platform
 
-from six.moves import map
+from pkg_resources.extern.six.moves import map
 
 import pytest
-import packaging
+from pkg_resources.extern import packaging
 
 import pkg_resources
 from pkg_resources import (parse_requirements, VersionConflict, parse_version,
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644 (file)
index 0aa2e1c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[build-system]
-# for Setuptools, its own requirements are build requirements,
-# so keep this in sync with install_requires in setup.py.
-requires = [
-    "wheel",
-    "packaging>=16.8",
-    "six>=1.10.0",
-    "appdirs>=1.4.0",
-]
index cb247aa..e39b524 100755 (executable)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 35.0.2
+current_version = 36.0.0
 commit = True
 tag = True
 
index 0d465cc..9250e07 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@ def require_metadata():
     if not os.path.exists(egg_info_dir):
         msg = (
             "Cannot build setuptools without metadata. "
-            "Install rwt and run `rwt -- bootstrap.py`."
+            "Run `bootstrap.py`."
         )
         raise RuntimeError(msg)
 
@@ -89,7 +89,7 @@ def pypi_link(pkg_filename):
 
 setup_params = dict(
     name="setuptools",
-    version="35.0.2",
+    version="36.0.0",
     description="Easily download, build, install, upgrade, and uninstall "
         "Python packages",
     author="Python Packaging Authority",
@@ -163,11 +163,6 @@ setup_params = dict(
         Topic :: Utilities
         """).strip().splitlines(),
     python_requires='>=2.6,!=3.0.*,!=3.1.*,!=3.2.*',
-    install_requires=[
-        'packaging>=16.8',
-        'six>=1.6.0',
-        'appdirs>=1.4.0',
-    ],
     extras_require={
         "ssl:sys_platform=='win32'": "wincertstore==0.2",
         "certs": "certifi==2016.9.26",
index d01918e..04f7674 100644 (file)
@@ -7,7 +7,7 @@ import distutils.filelist
 from distutils.util import convert_path
 from fnmatch import fnmatchcase
 
-from six.moves import filter, map
+from setuptools.extern.six.moves import filter, map
 
 import setuptools.version
 from setuptools.extension import Extension
index 35ece78..4532b1c 100755 (executable)
@@ -1,6 +1,6 @@
 from distutils.errors import DistutilsOptionError
 
-from six.moves import map
+from setuptools.extern.six.moves import map
 
 from setuptools.command.setopt import edit_config, option_base, config_file
 
index ae344cd..8cd9dfe 100644 (file)
@@ -11,7 +11,7 @@ import os
 import textwrap
 import marshal
 
-import six
+from setuptools.extern import six
 
 from pkg_resources import get_build_platform, Distribution, ensure_directory
 from pkg_resources import EntryPoint
index c2fd870..36f53f0 100644 (file)
@@ -10,7 +10,7 @@ from distutils.errors import DistutilsError
 from distutils import log
 
 from setuptools.extension import Library
-import six
+from setuptools.extern import six
 
 try:
     # Attempt to use Cython for building extensions, if available
index 56daa2b..b0314fd 100644 (file)
@@ -8,8 +8,8 @@ import io
 import distutils.errors
 import itertools
 
-import six
-from six.moves import map, filter, filterfalse
+from setuptools.extern import six
+from setuptools.extern.six.moves import map, filter, filterfalse
 
 try:
     from setuptools.lib2to3_ex import Mixin2to3
index ddfdc66..85b23c6 100755 (executable)
@@ -5,7 +5,7 @@ import os
 import glob
 import io
 
-import six
+from setuptools.extern import six
 
 from pkg_resources import Distribution, PathMetadata, normalize_path
 from setuptools.command.easy_install import easy_install
index e30ca3a..e319f77 100755 (executable)
@@ -40,8 +40,8 @@ import subprocess
 import shlex
 import io
 
-import six
-from six.moves import configparser, map
+from setuptools.extern import six
+from setuptools.extern.six.moves import configparser, map
 
 from setuptools import Command
 from setuptools.sandbox import run_setup
index 151e495..6c00b0b 100755 (executable)
@@ -16,8 +16,8 @@ import warnings
 import time
 import collections
 
-import six
-from six.moves import map
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
 
 from setuptools import Command
 from setuptools.command.sdist import sdist
@@ -30,7 +30,7 @@ from pkg_resources import (
 import setuptools.unicode_utils as unicode_utils
 from setuptools.glob import glob
 
-import packaging
+from pkg_resources.extern import packaging
 
 
 def translate_pattern(glob):
index a2c74b2..61063e7 100644 (file)
@@ -3,7 +3,7 @@ from glob import glob
 from distutils.util import convert_path
 from distutils.command import sdist
 
-from six.moves import filter
+from setuptools.extern.six.moves import filter
 
 
 class sdist_add_defaults:
index 7ea36e9..b89353f 100755 (executable)
@@ -4,7 +4,7 @@ from distutils.errors import DistutilsOptionError
 import os
 import shutil
 
-import six
+from setuptools.extern import six
 
 from setuptools import Command
 
index 2c2d88a..84e29a1 100755 (executable)
@@ -5,7 +5,7 @@ import sys
 import io
 import contextlib
 
-import six
+from setuptools.extern import six
 
 from .py36compat import sdist_add_defaults
 
index 6f6298c..7e57cc0 100755 (executable)
@@ -4,7 +4,7 @@ from distutils.errors import DistutilsOptionError
 import distutils
 import os
 
-from six.moves import configparser
+from setuptools.extern.six.moves import configparser
 
 from setuptools import Command
 
index e7a386d..b8863fd 100644 (file)
@@ -7,8 +7,8 @@ from distutils.errors import DistutilsError, DistutilsOptionError
 from distutils import log
 from unittest import TestLoader
 
-import six
-from six.moves import map, filter
+from setuptools.extern import six
+from setuptools.extern.six.moves import map, filter
 
 from pkg_resources import (resource_listdir, resource_exists, normalize_path,
                            working_set, _namespace_packages,
@@ -67,7 +67,7 @@ class test(Command):
     user_options = [
         ('test-module=', 'm', "Run 'test_suite' in specified module"),
         ('test-suite=', 's',
-         "Test suite to run (e.g. 'some_module.test_suite')"),
+         "Run single test, case or suite (e.g. 'module.test_suite')"),
         ('test-runner=', 'r', "Test runner to use"),
     ]
 
index 468cb37..24a017c 100644 (file)
@@ -16,8 +16,8 @@ import shutil
 import itertools
 import functools
 
-import six
-from six.moves import http_client, urllib
+from setuptools.extern import six
+from setuptools.extern.six.moves import http_client, urllib
 
 from pkg_resources import iter_entry_points
 from .upload import upload
index 252f2de..06a61d1 100644 (file)
@@ -7,7 +7,7 @@ from functools import partial
 
 from distutils.errors import DistutilsOptionError, DistutilsFileError
 from setuptools.py26compat import import_module
-from six import string_types
+from setuptools.extern.six import string_types
 
 
 def read_configuration(
index fd1d28c..6b97ed3 100644 (file)
@@ -12,10 +12,12 @@ from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
     DistutilsSetupError)
 from distutils.util import rfc822_escape
 
-import six
-from six.moves import map
-import packaging.specifiers
-import packaging.version
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
+from pkg_resources.extern import packaging
+
+__import__('pkg_resources.extern.packaging.specifiers')
+__import__('pkg_resources.extern.packaging.version')
 
 from setuptools.depends import Require
 from setuptools import windows_support
index 34a36df..2946889 100644 (file)
@@ -4,7 +4,7 @@ import distutils.core
 import distutils.errors
 import distutils.extension
 
-from six.moves import map
+from setuptools.extern.six.moves import map
 
 from .monkey import get_unpatched
 
diff --git a/setuptools/extern/__init__.py b/setuptools/extern/__init__.py
new file mode 100644 (file)
index 0000000..2cd08b7
--- /dev/null
@@ -0,0 +1,4 @@
+from pkg_resources.extern import VendorImporter
+
+names = 'six',
+VendorImporter(__name__, names, 'pkg_resources._vendor').install()
index f264402..6c781de 100644 (file)
@@ -10,7 +10,7 @@ Changes include:
 import os
 import re
 import fnmatch
-from six import binary_type
+from setuptools.extern.six import binary_type
 
 __all__ = ["glob", "iglob", "escape"]
 
index acd0a4f..6d3711e 100644 (file)
@@ -10,7 +10,7 @@ import functools
 import inspect
 
 from .py26compat import import_module
-import six
+from setuptools.extern import six
 
 import setuptools
 
index 84dcb2a..729021a 100644 (file)
@@ -22,14 +22,14 @@ import sys
 import platform
 import itertools
 import distutils.errors
-from packaging.version import LegacyVersion
+from pkg_resources.extern.packaging.version import LegacyVersion
 
-from six.moves import filterfalse
+from setuptools.extern.six.moves import filterfalse
 
 from .monkey import get_unpatched
 
 if platform.system() == 'Windows':
-    from six.moves import winreg
+    from setuptools.extern.six.moves import winreg
     safe_env = os.environ
 else:
     """
index 7c24a56..dc16106 100755 (executable)
@@ -2,7 +2,7 @@ import os
 from distutils import log
 import itertools
 
-from six.moves import map
+from setuptools.extern.six.moves import map
 
 
 flatten = itertools.chain.from_iterable
index 5d397b6..2acc817 100755 (executable)
@@ -14,8 +14,8 @@ try:
 except ImportError:
     from urllib2 import splituser
 
-import six
-from six.moves import urllib, http_client, configparser, map
+from setuptools.extern import six
+from setuptools.extern.six.moves import urllib, http_client, configparser, map
 
 import setuptools
 from pkg_resources import (
index 0caa200..af64d5d 100644 (file)
@@ -2,7 +2,7 @@ import dis
 import array
 import collections
 
-import six
+from setuptools.extern import six
 
 
 OpArg = collections.namedtuple('OpArg', 'opcode arg')
index 41c1c3b..f99c13c 100755 (executable)
@@ -7,9 +7,10 @@ import itertools
 import re
 import contextlib
 import pickle
+import textwrap
 
-import six
-from six.moves import builtins, map
+from setuptools.extern import six
+from setuptools.extern.six.moves import builtins, map
 
 import pkg_resources
 
@@ -248,11 +249,9 @@ def run_setup(setup_script, args):
                 setup_script.encode(sys.getfilesystemencoding())
             )
 
-            def runner():
+            with DirectorySandbox(setup_dir):
                 ns = dict(__file__=dunder_file, __name__='__main__')
                 _execfile(setup_script, ns)
-
-            DirectorySandbox(setup_dir).run(runner)
         except SystemExit as v:
             if v.args and v.args[0]:
                 raise
@@ -274,21 +273,24 @@ class AbstractSandbox:
         for name in self._attrs:
             setattr(os, name, getattr(source, name))
 
+    def __enter__(self):
+        self._copy(self)
+        if _file:
+            builtins.file = self._file
+        builtins.open = self._open
+        self._active = True
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self._active = False
+        if _file:
+            builtins.file = _file
+        builtins.open = _open
+        self._copy(_os)
+
     def run(self, func):
         """Run 'func' under os sandboxing"""
-        try:
-            self._copy(self)
-            if _file:
-                builtins.file = self._file
-            builtins.open = self._open
-            self._active = True
+        with self:
             return func()
-        finally:
-            self._active = False
-            if _file:
-                builtins.file = _file
-            builtins.open = _open
-            self._copy(_os)
 
     def _mk_dual_path_wrapper(name):
         original = getattr(_os, name)
@@ -476,16 +478,18 @@ WRITE_FLAGS = functools.reduce(
 class SandboxViolation(DistutilsError):
     """A setup script attempted to modify the filesystem outside the sandbox"""
 
-    def __str__(self):
-        return """SandboxViolation: %s%r %s
-
-The package setup script has attempted to modify files on your system
-that are not within the EasyInstall build area, and has been aborted.
+    tmpl = textwrap.dedent("""
+        SandboxViolation: {cmd}{args!r} {kwargs}
 
-This package cannot be safely installed by EasyInstall, and may not
-support alternate installation locations even if you run its setup
-script by hand.  Please inform the package's author and the EasyInstall
-maintainers to find out if a fix or workaround is available.""" % self.args
+        The package setup script has attempted to modify files on your system
+        that are not within the EasyInstall build area, and has been aborted.
 
+        This package cannot be safely installed by EasyInstall, and may not
+        support alternate installation locations even if you run its setup
+        script by hand.  Please inform the package's author and the EasyInstall
+        maintainers to find out if a fix or workaround is available.
+        """).lstrip()
 
-#
+    def __str__(self):
+        cmd, args, kwargs = self.args
+        return self.tmpl.format(**locals())
index fa5e442..72b18ef 100644 (file)
@@ -4,7 +4,7 @@ import atexit
 import re
 import functools
 
-from six.moves import urllib, http_client, map, filter
+from setuptools.extern.six.moves import urllib, http_client, map, filter
 
 from pkg_resources import ResolutionError, ExtractionError
 
index f54c478..dbf1620 100644 (file)
@@ -8,7 +8,7 @@ from distutils.errors import DistutilsSetupError
 from distutils.core import Extension
 from distutils.version import LooseVersion
 
-import six
+from setuptools.extern import six
 import pytest
 
 import setuptools.dist
index 77ebecf..535ae10 100644 (file)
@@ -5,7 +5,7 @@ import sys
 import contextlib
 import site
 
-import six
+from setuptools.extern import six
 import pkg_resources
 
 
index 5cdde21..3531212 100644 (file)
@@ -4,7 +4,7 @@
 import time
 import threading
 
-from six.moves import BaseHTTPServer, SimpleHTTPServer
+from setuptools.extern.six.moves import BaseHTTPServer, SimpleHTTPServer
 
 
 class IndexServer(BaseHTTPServer.HTTPServer):
index 5cdf63f..b789e9a 100644 (file)
@@ -3,7 +3,7 @@
 import tarfile
 import io
 
-import six
+from setuptools.extern import six
 
 import pytest
 
index 59a896d..6025715 100644 (file)
@@ -2,7 +2,7 @@ import sys
 import distutils.command.build_ext as orig
 from distutils.sysconfig import get_config_var
 
-import six
+from setuptools.extern import six
 
 from setuptools.command.build_ext import build_ext, get_abi3_suffix
 from setuptools.dist import Distribution
index 54e199c..ad7cfa0 100644 (file)
@@ -9,7 +9,7 @@ import sys
 import io
 import subprocess
 
-import six
+from setuptools.extern import six
 from setuptools.command import test
 
 import pytest
index 24c5149..f7e7d2b 100644 (file)
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 
-from six.moves import map
+from setuptools.extern.six.moves import map
 
 import pytest
 
index fd8300a..2d9682a 100644 (file)
@@ -17,7 +17,7 @@ import zipfile
 from unittest import mock
 
 import time
-from six.moves import urllib
+from setuptools.extern.six.moves import urllib
 
 import pytest
 
index c9a4425..a32b981 100644 (file)
@@ -6,7 +6,7 @@ import sys
 
 from setuptools.command.egg_info import egg_info, manifest_maker
 from setuptools.dist import Distribution
-from six.moves import map
+from setuptools.extern.six.moves import map
 
 import pytest
 
index 2acec91..3a9a6c5 100644 (file)
@@ -7,7 +7,7 @@ import glob
 import os
 import sys
 
-from six.moves import urllib
+from setuptools.extern.six.moves import urllib
 import pytest
 
 from setuptools.command.easy_install import easy_install
index 28cbca1..ab9b346 100644 (file)
@@ -12,7 +12,7 @@ from distutils.errors import DistutilsTemplateError
 
 from setuptools.command.egg_info import FileList, egg_info, translate_pattern
 from setuptools.dist import Distribution
-import six
+from setuptools.extern import six
 from setuptools.tests.textwrap import DALS
 
 import pytest
index 1a66394..53e20d4 100644 (file)
@@ -4,8 +4,8 @@ import sys
 import os
 import distutils.errors
 
-import six
-from six.moves import urllib, http_client
+from setuptools.extern import six
+from setuptools.extern.six.moves import urllib, http_client
 
 import pkg_resources
 import setuptools.package_index
index 929f0a5..a3f1206 100644 (file)
@@ -7,13 +7,12 @@ import pytest
 
 import pkg_resources
 import setuptools.sandbox
-from setuptools.sandbox import DirectorySandbox
 
 
 class TestSandbox:
     def test_devnull(self, tmpdir):
-        sandbox = DirectorySandbox(str(tmpdir))
-        sandbox.run(self._file_writer(os.devnull))
+        with setuptools.sandbox.DirectorySandbox(str(tmpdir)):
+            self._file_writer(os.devnull)
 
     @staticmethod
     def _file_writer(path):
@@ -116,13 +115,17 @@ class TestExceptionSaver:
             with open('/etc/foo', 'w'):
                 pass
 
-        sandbox = DirectorySandbox(str(tmpdir))
         with pytest.raises(setuptools.sandbox.SandboxViolation) as caught:
             with setuptools.sandbox.save_modules():
                 setuptools.sandbox.hide_setuptools()
-                sandbox.run(write_file)
+                with setuptools.sandbox.DirectorySandbox(str(tmpdir)):
+                    write_file()
 
         cmd, args, kwargs = caught.value.args
         assert cmd == 'open'
         assert args == ('/etc/foo', 'w')
         assert kwargs == {}
+
+        msg = str(caught.value)
+        assert 'open' in msg
+        assert "('/etc/foo', 'w')" in msg
index 38fdda2..f34068d 100644 (file)
@@ -9,8 +9,8 @@ import unicodedata
 import contextlib
 import io
 
-import six
-from six.moves import map
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
 
 import pytest
 
index 6a84f9b..7c63efd 100644 (file)
@@ -1,7 +1,7 @@
 import unicodedata
 import sys
 
-import six
+from setuptools.extern import six
 
 
 # HFS Plus uses decomposed UTF-8
index 88a36c6..6e2e78e 100644 (file)
@@ -1,3 +1,4 @@
 pytest-flake8
 pytest>=3.0.2
-backports.unittest_mock>=1.2
+# pinned to 1.2 as temporary workaround for #1038
+backports.unittest_mock>=1.2,<1.3
index 173b2c8..b3425e5 100644 (file)
@@ -2,8 +2,8 @@ import os
 import subprocess
 
 import virtualenv
-from six.moves import http_client
-from six.moves import xmlrpc_client
+from setuptools.extern.six.moves import http_client
+from setuptools.extern.six.moves import xmlrpc_client
 
 TOP = 200
 PYPI_HOSTNAME = 'pypi.python.org'
diff --git a/tox.ini b/tox.ini
index 6b43dcd..c3ea462 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,11 @@
+# Note: Run "python bootstrap.py" before running Tox, to generate metadata.
+#
+# To run Tox against all supported Python interpreters, you can set:
+#
+# export TOXENV='py2{6,7},py3{3,4,5,6},pypy'
+
 [testenv]
-deps=
-    -rtests/requirements.txt
-    -rrequirements.txt
+deps=-rtests/requirements.txt
 passenv=APPDATA USERPROFILE HOMEDRIVE HOMEPATH windir APPVEYOR
 commands=py.test {posargs:-rsx}
 usedevelop=True
-extras=ssl