Imported Upstream version 63.4.2 upstream/63.4.2
authorJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:53 +0000 (17:02 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:53 +0000 (17:02 +0900)
53 files changed:
.bumpversion.cfg
CHANGES.rst
docs/conf.py
docs/userguide/extension.rst
docs/userguide/package_discovery.rst
docs/userguide/pyproject_config.rst
docs/userguide/quickstart.rst
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/INSTALLER [new file with mode: 0644]
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/LICENSE [new file with mode: 0644]
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/METADATA [new file with mode: 0644]
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/RECORD [new file with mode: 0644]
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/REQUESTED [new file with mode: 0644]
pkg_resources/_vendor/pyparsing-3.0.9.dist-info/WHEEL [new file with mode: 0644]
pkg_resources/_vendor/pyparsing/__init__.py
pkg_resources/_vendor/pyparsing/actions.py
pkg_resources/_vendor/pyparsing/core.py
pkg_resources/_vendor/pyparsing/diagram/__init__.py
pkg_resources/_vendor/pyparsing/diagram/template.jinja2 [deleted file]
pkg_resources/_vendor/pyparsing/exceptions.py
pkg_resources/_vendor/pyparsing/helpers.py
pkg_resources/_vendor/pyparsing/results.py
pkg_resources/_vendor/pyparsing/testing.py
pkg_resources/_vendor/pyparsing/unicode.py
pkg_resources/_vendor/vendored.txt
setup.cfg
setuptools/_vendor/pyparsing-3.0.8.dist-info/INSTALLER [deleted file]
setuptools/_vendor/pyparsing-3.0.8.dist-info/LICENSE [deleted file]
setuptools/_vendor/pyparsing-3.0.8.dist-info/METADATA [deleted file]
setuptools/_vendor/pyparsing-3.0.8.dist-info/RECORD [deleted file]
setuptools/_vendor/pyparsing-3.0.8.dist-info/REQUESTED [deleted file]
setuptools/_vendor/pyparsing-3.0.8.dist-info/WHEEL [deleted file]
setuptools/_vendor/pyparsing-3.0.9.dist-info/INSTALLER [new file with mode: 0644]
setuptools/_vendor/pyparsing-3.0.9.dist-info/LICENSE [new file with mode: 0644]
setuptools/_vendor/pyparsing-3.0.9.dist-info/METADATA [new file with mode: 0644]
setuptools/_vendor/pyparsing-3.0.9.dist-info/RECORD [new file with mode: 0644]
setuptools/_vendor/pyparsing-3.0.9.dist-info/REQUESTED [new file with mode: 0644]
setuptools/_vendor/pyparsing-3.0.9.dist-info/WHEEL [new file with mode: 0644]
setuptools/_vendor/pyparsing/__init__.py
setuptools/_vendor/pyparsing/actions.py
setuptools/_vendor/pyparsing/core.py
setuptools/_vendor/pyparsing/diagram/__init__.py
setuptools/_vendor/pyparsing/diagram/template.jinja2 [deleted file]
setuptools/_vendor/pyparsing/exceptions.py
setuptools/_vendor/pyparsing/helpers.py
setuptools/_vendor/pyparsing/results.py
setuptools/_vendor/pyparsing/testing.py
setuptools/_vendor/pyparsing/unicode.py
setuptools/_vendor/vendored.txt
setuptools/config/pyprojecttoml.py
setuptools/config/setupcfg.py
setuptools/extension.py
setuptools/tests/config/test_pyprojecttoml.py
setuptools/tests/config/test_setupcfg.py

index f462bfadee8e80fe535d1c00354f8e7ae5ae544d..d25ccab37e1a15cdb1985954a36c7c39ef8e7fae 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 63.4.1
+current_version = 63.4.2
 commit = True
 tag = True
 
index eca0fc0562e95e12dc3bdca80dad583f476868a8..9244bc6d53c615261ae426bb574a4c31eac7b516 100644 (file)
@@ -1,3 +1,16 @@
+v63.4.2
+-------
+
+
+Misc
+^^^^
+* #3453: Bump vendored version of :pypi:`pyparsing` to 3.0.9.
+* #3481: Add warning for potential ``install_requires`` and ``extras_require``
+  misconfiguration in ``setup.cfg``
+* #3487: Modified ``pyproject.toml`` validation exception handling to
+  make relevant debugging information easier to spot.
+
+
 v63.4.1
 -------
 
@@ -67,7 +80,7 @@ Breaking Changes
 ^^^^^^^^^^^^^^^^
 * #3421: Drop setuptools' support for installing an entrypoint extra requirements at load time:
   - the functionality has been broken since v60.8.0.
-  - the mechanism to do so is deprecated (`fetch_build_eggs`).
+  - the mechanism to do so is deprecated (``fetch_build_eggs``).
   - that use case (e.g. a custom command class entrypoint) is covered by making sure the necessary build requirements are declared.
 
 Documentation changes
index 9a4e33b77c5901516e62c51e70a3d701174781cc..2b60bf57b2d7b4b1175fdeb41cc59894b76bc5f0 100644 (file)
@@ -186,6 +186,7 @@ nitpick_ignore = [
     ('py:exc', 'LibError'),  # undocumented
     ('py:exc', 'LinkError'),  # undocumented
     ('py:exc', 'PreprocessError'),  # undocumented
+    ('py:exc', 'setuptools.errors.PlatformError'),  # sphinx cannot find it
     ('py:func', 'distutils.CCompiler.new_compiler'),  # undocumented
     # undocumented:
     ('py:func', 'distutils.dist.DistributionMetadata.read_pkg_file'),
index 0008b6c2fc57a20e234ec3b9f2769c545e87d828..31d32d61747267a7da215477cea040888ac38c29 100644 (file)
@@ -103,20 +103,20 @@ The idea here is that the entry point defines a function that will be called
 to validate the ``setup()`` argument, if it's supplied.  The ``Distribution``
 object will have the initial value of the attribute set to ``None``, and the
 validation function will only be called if the ``setup()`` call sets it to
-a non-None value.  Here's an example validation function::
+a non-``None`` value.  Here's an example validation function::
 
     def assert_bool(dist, attr, value):
         """Verify that value is True, False, 0, or 1"""
         if bool(value) != value:
-            raise DistutilsSetupError(
+            raise SetupError(
                 "%r must be a boolean value (got %r)" % (attr,value)
             )
 
 Your function should accept three arguments: the ``Distribution`` object,
 the attribute name, and the attribute value.  It should raise a
 ``SetupError`` (from the ``setuptools.errors`` module) if the argument
-is invalid.  Remember, your function will only be called with non-None values,
-and the default value of arguments defined this way is always None.  So, your
+is invalid.  Remember, your function will only be called with non-``None`` values,
+and the default value of arguments defined this way is always ``None``.  So, your
 commands should always be prepared for the possibility that the attribute will
 be ``None`` when they access it later.
 
@@ -129,12 +129,12 @@ what values of that argument are valid.
 Customizing Distribution Options
 --------------------------------
 
-Plugins may wish to extend or alter the options on a Distribution object to
+Plugins may wish to extend or alter the options on a ``Distribution`` object to
 suit the purposes of that project. For example, a tool that infers the
 ``Distribution.version`` from SCM-metadata may need to hook into the
 option finalization. To enable this feature, Setuptools offers an entry
-point "setuptools.finalize_distribution_options". That entry point must
-be a callable taking one argument (the Distribution instance).
+point ``setuptools.finalize_distribution_options``. That entry point must
+be a callable taking one argument (the ``Distribution`` instance).
 
 If the callable has an ``.order`` property, that value will be used to
 determine the order in which the hook is called. Lower numbers are called
index 2efc62b9ebc803cfe5f52a48507308a9b4e90785..7dda84a88243768c189e5cd85229ae55f47d5084 100644 (file)
@@ -279,7 +279,7 @@ the provided tools for package discovery:
         [tool.setuptools.packages]
         find = {}  # Scanning implicit namespaces is active by default
         # OR
-        find = {namespace = false}  # Disable implicit namespaces
+        find = {namespaces = false}  # Disable implicit namespaces
 
 
 Finding simple packages
index 28eb39d1a30e6e6667379dc04231bd9516e259c3..709bf91946a5de0dfca34fbef832531df4a1c3be 100644 (file)
@@ -7,8 +7,8 @@ Configuring setuptools using ``pyproject.toml`` files
 .. note:: New in 61.0.0
 
 .. important::
-   For the time being, ``pip`` still might require a ``setup.py`` file
-   to support :doc:`editable installs <pip:cli/pip_install>`.
+   For the time being [#pep660-status]_, ``pip`` still might require a ``setup.py`` file
+   to support :doc:`editable installs <pip:cli/pip_install>` [#setupcfg-caveats]_.
 
    A simple script will suffice, for example:
 
@@ -214,6 +214,13 @@ however please keep in mind that all non-comment lines must conform with :pep:`5
 
 .. rubric:: Notes
 
+.. [#pep660-status] Editable install without ``setup.py`` will be supported in
+   future versions of ``setuptools``. Check https://github.com/pypa/setuptools/issues/2816 for detail.
+
+.. [#setupcfg-caveats] ``pip`` may allow editable install only with ``pyproject.toml``
+   and ``setup.cfg``. However, this behavior may not be consistent over various build
+   tools. Having a ``setup.py`` is still recommended if you rely on one of these tools.
+
 .. [#entry-points] Dynamic ``scripts`` and ``gui-scripts`` are a special case.
    When resolving these metadata keys, ``setuptools`` will look for
    ``tool.setuptool.dynamic.entry-points``, and use the values of the
index 060288d8d1513c25fe8caf9a139d7535e82fcc91..24c71b8e52675dc3b0f7de3fbf55eeacbb40f7ee 100644 (file)
@@ -176,6 +176,7 @@ found, as shown in the example below:
 
         # OR
         [tool.setuptools.packages.find]
+        # All the following settings are optional:
         where = ["src"]  # ["."] by default
         include = ["mypackage*"]  # ["*"] by default
         exclude = ["mypackage.tests*"]  # empty by default
@@ -188,12 +189,11 @@ found, as shown in the example below:
         [options]
         packages = find: # OR `find_namespace:` if you want to use namespaces
 
-        [options.packages.find] # (always `find` even if `find_namespace:` was used before)
-        # This section is optional
-        # Each entry in this section is optional, and if not specified, the default values are:
-        # `where=.`, `include=*` and `exclude=` (empty).
-        include=mypackage*
-        exclude=mypackage.tests*
+        [options.packages.find]  # (always `find` even if `find_namespace:` was used before)
+        # This section is optional as well as each of the following options:
+        where=src  # . by default
+        include=mypackage*  # * by default
+        exclude=mypackage.tests*  # empty by default
 
 .. tab:: setup.py [#setup.py]_
 
@@ -204,18 +204,18 @@ found, as shown in the example below:
         setup(
             # ...
             packages=find_packages(
-                where='.',
-                include=['mypackage*'],  # ["*"] by default
+                # All keyword arguments below are optional:
+                where='src',  # '.' by default
+                include=['mypackage*'],  # ['*'] by default
                 exclude=['mypackage.tests'],  # empty by default
             ),
             # ...
         )
 
 When you pass the above information, alongside other necessary information,
-``setuptools`` walks through the directory specified in ``where`` (omitted
-here as the package resides in the current directory) and filters the packages
+``setuptools`` walks through the directory specified in ``where`` (defaults to ``.``) and filters the packages
 it can find following the ``include`` patterns (defaults to ``*``), then it removes
-those that match the ``exclude`` patterns and returns a list of Python packages.
+those that match the ``exclude`` patterns (defaults to empty) and returns a list of Python packages.
 
 For more details and advanced use, go to :ref:`package_discovery`.
 
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/INSTALLER b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/INSTALLER
new file mode 100644 (file)
index 0000000..a1b589e
--- /dev/null
@@ -0,0 +1 @@
+pip
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/LICENSE b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/LICENSE
new file mode 100644 (file)
index 0000000..1bf9852
--- /dev/null
@@ -0,0 +1,18 @@
+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.
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/METADATA b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/METADATA
new file mode 100644 (file)
index 0000000..33e5194
--- /dev/null
@@ -0,0 +1,105 @@
+Metadata-Version: 2.1
+Name: pyparsing
+Version: 3.0.9
+Summary: pyparsing module - Classes and methods to define and execute parsing grammars
+Author-email: Paul McGuire <ptmcg.gm+pyparsing@gmail.com>
+Requires-Python: >=3.6.8
+Description-Content-Type: text/x-rst
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Typing :: Typed
+Requires-Dist: railroad-diagrams ; extra == "diagrams"
+Requires-Dist: jinja2 ; extra == "diagrams"
+Project-URL: Homepage, https://github.com/pyparsing/pyparsing/
+Provides-Extra: diagrams
+
+PyParsing -- A Python Parsing Module
+====================================
+
+|Build Status| |Coverage|
+
+Introduction
+============
+
+The pyparsing module is an alternative approach to creating and
+executing simple grammars, vs. the traditional lex/yacc approach, or the
+use of regular expressions. The pyparsing module provides a library of
+classes that client code uses to construct the grammar directly in
+Python code.
+
+*[Since first writing this description of pyparsing in late 2003, this
+technique for developing parsers has become more widespread, under the
+name Parsing Expression Grammars - PEGs. See more information on PEGs*
+`here <https://en.wikipedia.org/wiki/Parsing_expression_grammar>`__
+*.]*
+
+Here is a program to parse ``"Hello, World!"`` (or any greeting of the form
+``"salutation, addressee!"``):
+
+.. code:: python
+
+    from pyparsing import Word, alphas
+    greet = Word(alphas) + "," + Word(alphas) + "!"
+    hello = "Hello, World!"
+    print(hello, "->", greet.parseString(hello))
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the
+self-explanatory class names, and the use of '+', '|' and '^' operator
+definitions.
+
+The parsed results returned from ``parseString()`` is a collection of type
+``ParseResults``, which can be accessed as a
+nested list, a dictionary, or an object with named attributes.
+
+The pyparsing module handles some of the problems that are typically
+vexing when writing text parsers:
+
+- extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.)
+- quoted strings
+- embedded comments
+
+The examples directory includes a simple SQL parser, simple CORBA IDL
+parser, a config file parser, a chemical formula parser, and a four-
+function algebraic notation parser, among many others.
+
+Documentation
+=============
+
+There are many examples in the online docstrings of the classes
+and methods in pyparsing. You can find them compiled into `online docs <https://pyparsing-docs.readthedocs.io/en/latest/>`__. Additional
+documentation resources and project info are listed in the online
+`GitHub wiki <https://github.com/pyparsing/pyparsing/wiki>`__. An
+entire directory of examples can be found `here <https://github.com/pyparsing/pyparsing/tree/master/examples>`__.
+
+License
+=======
+
+MIT License. See header of the `pyparsing.py <https://github.com/pyparsing/pyparsing/blob/master/pyparsing/__init__.py#L1-L23>`__ file.
+
+History
+=======
+
+See `CHANGES <https://github.com/pyparsing/pyparsing/blob/master/CHANGES>`__ file.
+
+.. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg
+   :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml
+.. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg
+  :target: https://codecov.io/gh/pyparsing/pyparsing
+
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/RECORD b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/RECORD
new file mode 100644 (file)
index 0000000..7a4e49a
--- /dev/null
@@ -0,0 +1,29 @@
+pyparsing-3.0.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+pyparsing-3.0.9.dist-info/LICENSE,sha256=ENUSChaAWAT_2otojCIL-06POXQbVzIGBNRVowngGXI,1023
+pyparsing-3.0.9.dist-info/METADATA,sha256=h_fpm9rwvgZsE8v5YNF4IAo-IpaFWCOfUEm5MMByIiM,4207
+pyparsing-3.0.9.dist-info/RECORD,,
+pyparsing-3.0.9.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pyparsing-3.0.9.dist-info/WHEEL,sha256=jPMR_Dzkc4X4icQtmz81lnNY_kAsfog7ry7qoRvYLXw,81
+pyparsing/__init__.py,sha256=52QH3lgPbJhba0estckoGPHRH8JvQSSCGoWiEn2m0bU,9159
+pyparsing/__pycache__/__init__.cpython-38.pyc,,
+pyparsing/__pycache__/actions.cpython-38.pyc,,
+pyparsing/__pycache__/common.cpython-38.pyc,,
+pyparsing/__pycache__/core.cpython-38.pyc,,
+pyparsing/__pycache__/exceptions.cpython-38.pyc,,
+pyparsing/__pycache__/helpers.cpython-38.pyc,,
+pyparsing/__pycache__/results.cpython-38.pyc,,
+pyparsing/__pycache__/testing.cpython-38.pyc,,
+pyparsing/__pycache__/unicode.cpython-38.pyc,,
+pyparsing/__pycache__/util.cpython-38.pyc,,
+pyparsing/actions.py,sha256=wU9i32e0y1ymxKE3OUwSHO-SFIrt1h_wv6Ws0GQjpNU,6426
+pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936
+pyparsing/core.py,sha256=u8GptQE_H6wMkl8OZhxeK1aAPIDXXNgwdShORBwBVS4,213310
+pyparsing/diagram/__init__.py,sha256=f_EfxahqrdkRVahmTwLJXkZ9EEDKNd-O7lBbpJYlE1g,23668
+pyparsing/diagram/__pycache__/__init__.cpython-38.pyc,,
+pyparsing/exceptions.py,sha256=3LbSafD32NYb1Tzt85GHNkhEAU1eZkTtNSk24cPMemo,9023
+pyparsing/helpers.py,sha256=QpUOjW0-psvueMwWb9bQpU2noqKCv98_wnw1VSzSdVo,39129
+pyparsing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pyparsing/results.py,sha256=HgNvWVXBdQP-Q6PtJfoCEeOJk2nwEvG-2KVKC5sGA30,25341
+pyparsing/testing.py,sha256=7tu4Abp4uSeJV0N_yEPRmmNUhpd18ZQP3CrX41DM814,13402
+pyparsing/unicode.py,sha256=fwuhMj30SQ165Cv7HJpu-rSxGbRm93kN9L4Ei7VGc1Y,10787
+pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/REQUESTED b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/REQUESTED
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/WHEEL b/pkg_resources/_vendor/pyparsing-3.0.9.dist-info/WHEEL
new file mode 100644 (file)
index 0000000..c727d14
--- /dev/null
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: flit 3.6.0
+Root-Is-Purelib: true
+Tag: py3-none-any
index 45f334d043fc72a77eef992cb4b2508f53837e2e..7802ff158d83eb88e6dbe78d9cd33ca14341662a 100644 (file)
@@ -128,8 +128,8 @@ class version_info(NamedTuple):
         )
 
 
-__version_info__ = version_info(3, 0, 8, "final", 0)
-__version_time__ = "09 Apr 2022 23:29 UTC"
+__version_info__ = version_info(3, 0, 9, "final", 0)
+__version_time__ = "05 May 2022 07:02 UTC"
 __version__ = __version_info__.__version__
 __versionTime__ = __version_time__
 __author__ = "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>"
index 2bcc5502b075ff39be828a05f9bdc2ea3e574cf0..f72c66e743146c7a5b70a5440e9ab5459f10245b 100644 (file)
@@ -55,7 +55,7 @@ def replace_with(repl_str):
         na = one_of("N/A NA").set_parse_action(replace_with(math.nan))
         term = na | num
 
-        OneOrMore(term).parse_string("324 234 N/A 234") # -> [324, 234, nan, 234]
+        term[1, ...].parse_string("324 234 N/A 234") # -> [324, 234, nan, 234]
     """
     return lambda s, l, t: [repl_str]
 
index 454bd57d0419439944b455c9c06958a97e7c8925..9acba3f3e984b404f52702964805732f03965048 100644 (file)
@@ -2,9 +2,8 @@
 # core.py
 #
 import os
+import typing
 from typing import (
-    Optional as OptionalType,
-    Iterable as IterableType,
     NamedTuple,
     Union,
     Callable,
@@ -14,7 +13,6 @@ from typing import (
     List,
     TextIO,
     Set,
-    Dict as DictType,
     Sequence,
 )
 from abc import ABC, abstractmethod
@@ -192,7 +190,7 @@ del __config_flags
 
 
 def _should_enable_warnings(
-    cmd_line_warn_options: IterableType[str], warn_env_var: OptionalType[str]
+    cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str]
 ) -> bool:
     enable = bool(warn_env_var)
     for warn_opt in cmd_line_warn_options:
@@ -404,7 +402,7 @@ class ParserElement(ABC):
 
     DEFAULT_WHITE_CHARS: str = " \n\t\r"
     verbose_stacktrace: bool = False
-    _literalStringClass: OptionalType[type] = None
+    _literalStringClass: typing.Optional[type] = None
 
     @staticmethod
     def set_default_whitespace_chars(chars: str) -> None:
@@ -414,11 +412,11 @@ class ParserElement(ABC):
         Example::
 
             # default whitespace chars are space, <TAB> and newline
-            OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
+            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
 
             # change to just treat newline as significant
             ParserElement.set_default_whitespace_chars(" \t")
-            OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
+            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
         """
         ParserElement.DEFAULT_WHITE_CHARS = chars
 
@@ -450,13 +448,13 @@ class ParserElement(ABC):
         ParserElement._literalStringClass = cls
 
     class DebugActions(NamedTuple):
-        debug_try: OptionalType[DebugStartAction]
-        debug_match: OptionalType[DebugSuccessAction]
-        debug_fail: OptionalType[DebugExceptionAction]
+        debug_try: typing.Optional[DebugStartAction]
+        debug_match: typing.Optional[DebugSuccessAction]
+        debug_fail: typing.Optional[DebugExceptionAction]
 
     def __init__(self, savelist: bool = False):
         self.parseAction: List[ParseAction] = list()
-        self.failAction: OptionalType[ParseFailAction] = None
+        self.failAction: typing.Optional[ParseFailAction] = None
         self.customName = None
         self._defaultName = None
         self.resultsName = None
@@ -510,7 +508,7 @@ class ParserElement(ABC):
             integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K")
             integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
 
-            print(OneOrMore(integerK | integerM | integer).parse_string("5K 100 640K 256M"))
+            print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M"))
 
         prints::
 
@@ -895,7 +893,7 @@ class ParserElement(ABC):
 
     # cache for left-recursion in Forward references
     recursion_lock = RLock()
-    recursion_memos: DictType[
+    recursion_memos: typing.Dict[
         Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]]
     ] = {}
 
@@ -985,7 +983,7 @@ class ParserElement(ABC):
 
     @staticmethod
     def enable_left_recursion(
-        cache_size_limit: OptionalType[int] = None, *, force=False
+        cache_size_limit: typing.Optional[int] = None, *, force=False
     ) -> None:
         """
         Enables "bounded recursion" parsing, which allows for both direct and indirect
@@ -1738,7 +1736,7 @@ class ParserElement(ABC):
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
             patt.parse_string('ablaj /* comment */ lskjd')
             # -> ['ablaj']
 
@@ -1798,7 +1796,7 @@ class ParserElement(ABC):
             # turn on debugging for wd
             wd.set_debug()
 
-            OneOrMore(term).parse_string("abc 123 xyz 890")
+            term[1, ...].parse_string("abc 123 xyz 890")
 
         prints::
 
@@ -1953,12 +1951,12 @@ class ParserElement(ABC):
         self,
         tests: Union[str, List[str]],
         parse_all: bool = True,
-        comment: OptionalType[Union["ParserElement", str]] = "#",
+        comment: typing.Optional[Union["ParserElement", str]] = "#",
         full_dump: bool = True,
         print_results: bool = True,
         failure_tests: bool = False,
         post_parse: Callable[[str, ParseResults], str] = None,
-        file: OptionalType[TextIO] = None,
+        file: typing.Optional[TextIO] = None,
         with_line_numbers: bool = False,
         *,
         parseAll: bool = True,
@@ -2385,11 +2383,11 @@ class Keyword(Token):
     def __init__(
         self,
         match_string: str = "",
-        ident_chars: OptionalType[str] = None,
+        ident_chars: typing.Optional[str] = None,
         caseless: bool = False,
         *,
         matchString: str = "",
-        identChars: OptionalType[str] = None,
+        identChars: typing.Optional[str] = None,
     ):
         super().__init__()
         identChars = identChars or ident_chars
@@ -2479,7 +2477,7 @@ class CaselessLiteral(Literal):
 
     Example::
 
-        OneOrMore(CaselessLiteral("CMD")).parse_string("cmd CMD Cmd10")
+        CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10")
         # -> ['CMD', 'CMD', 'CMD']
 
     (Contrast with example for :class:`CaselessKeyword`.)
@@ -2504,7 +2502,7 @@ class CaselessKeyword(Keyword):
 
     Example::
 
-        OneOrMore(CaselessKeyword("CMD")).parse_string("cmd CMD Cmd10")
+        CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10")
         # -> ['CMD', 'CMD']
 
     (Contrast with example for :class:`CaselessLiteral`.)
@@ -2513,10 +2511,10 @@ class CaselessKeyword(Keyword):
     def __init__(
         self,
         match_string: str = "",
-        ident_chars: OptionalType[str] = None,
+        ident_chars: typing.Optional[str] = None,
         *,
         matchString: str = "",
-        identChars: OptionalType[str] = None,
+        identChars: typing.Optional[str] = None,
     ):
         identChars = identChars or ident_chars
         match_string = matchString or match_string
@@ -2680,17 +2678,17 @@ class Word(Token):
     def __init__(
         self,
         init_chars: str = "",
-        body_chars: OptionalType[str] = None,
+        body_chars: typing.Optional[str] = None,
         min: int = 1,
         max: int = 0,
         exact: int = 0,
         as_keyword: bool = False,
-        exclude_chars: OptionalType[str] = None,
+        exclude_chars: typing.Optional[str] = None,
         *,
-        initChars: OptionalType[str] = None,
-        bodyChars: OptionalType[str] = None,
+        initChars: typing.Optional[str] = None,
+        bodyChars: typing.Optional[str] = None,
         asKeyword: bool = False,
-        excludeChars: OptionalType[str] = None,
+        excludeChars: typing.Optional[str] = None,
     ):
         initChars = initChars or init_chars
         bodyChars = bodyChars or body_chars
@@ -2872,10 +2870,10 @@ class Char(_WordRegex):
         self,
         charset: str,
         as_keyword: bool = False,
-        exclude_chars: OptionalType[str] = None,
+        exclude_chars: typing.Optional[str] = None,
         *,
         asKeyword: bool = False,
-        excludeChars: OptionalType[str] = None,
+        excludeChars: typing.Optional[str] = None,
     ):
         asKeyword = asKeyword or as_keyword
         excludeChars = excludeChars or exclude_chars
@@ -3088,18 +3086,18 @@ class QuotedString(Token):
     def __init__(
         self,
         quote_char: str = "",
-        esc_char: OptionalType[str] = None,
-        esc_quote: OptionalType[str] = None,
+        esc_char: typing.Optional[str] = None,
+        esc_quote: typing.Optional[str] = None,
         multiline: bool = False,
         unquote_results: bool = True,
-        end_quote_char: OptionalType[str] = None,
+        end_quote_char: typing.Optional[str] = None,
         convert_whitespace_escapes: bool = True,
         *,
         quoteChar: str = "",
-        escChar: OptionalType[str] = None,
-        escQuote: OptionalType[str] = None,
+        escChar: typing.Optional[str] = None,
+        escQuote: typing.Optional[str] = None,
         unquoteResults: bool = True,
-        endQuoteChar: OptionalType[str] = None,
+        endQuoteChar: typing.Optional[str] = None,
         convertWhitespaceEscapes: bool = True,
     ):
         super().__init__()
@@ -3600,7 +3598,7 @@ class ParseExpression(ParserElement):
     post-processing parsed tokens.
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(savelist)
         self.exprs: List[ParserElement]
         if isinstance(exprs, _generatorType):
@@ -3767,7 +3765,7 @@ class And(ParseExpression):
     Example::
 
         integer = Word(nums)
-        name_expr = OneOrMore(Word(alphas))
+        name_expr = Word(alphas)[1, ...]
 
         expr = And([integer("id"), name_expr("name"), integer("age")])
         # more easily written as:
@@ -3782,7 +3780,9 @@ class And(ParseExpression):
         def _generateDefaultName(self):
             return "-"
 
-    def __init__(self, exprs_arg: IterableType[ParserElement], savelist: bool = True):
+    def __init__(
+        self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True
+    ):
         exprs: List[ParserElement] = list(exprs_arg)
         if exprs and Ellipsis in exprs:
             tmp = []
@@ -3926,7 +3926,7 @@ class Or(ParseExpression):
         [['123'], ['3.1416'], ['789']]
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
@@ -4081,7 +4081,7 @@ class MatchFirst(ParseExpression):
         print(number.search_string("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
@@ -4232,7 +4232,7 @@ class Each(ParseExpression):
         - size: 20
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = True):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
@@ -4568,7 +4568,7 @@ class FollowedBy(ParseElementEnhance):
         label = data_word + FollowedBy(':')
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
 
-        OneOrMore(attr_expr).parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()
+        attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()
 
     prints::
 
@@ -4619,7 +4619,7 @@ class PrecededBy(ParseElementEnhance):
     """
 
     def __init__(
-        self, expr: Union[ParserElement, str], retreat: OptionalType[int] = None
+        self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None
     ):
         super().__init__(expr)
         self.expr = self.expr().leave_whitespace()
@@ -4730,7 +4730,7 @@ class NotAny(ParseElementEnhance):
 
         # very crude boolean expression - to support parenthesis groups and
         # operation hierarchy, use infix_notation
-        boolean_expr = boolean_term + ZeroOrMore((AND | OR) + boolean_term)
+        boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...]
 
         # integers that are followed by "." are actually floats
         integer = Word(nums) + ~Char(".")
@@ -4758,9 +4758,9 @@ class _MultipleMatch(ParseElementEnhance):
     def __init__(
         self,
         expr: ParserElement,
-        stop_on: OptionalType[Union[ParserElement, str]] = None,
+        stop_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
-        stopOn: OptionalType[Union[ParserElement, str]] = None,
+        stopOn: typing.Optional[Union[ParserElement, str]] = None,
     ):
         super().__init__(expr)
         stopOn = stopOn or stop_on
@@ -4849,7 +4849,7 @@ class OneOrMore(_MultipleMatch):
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join))
 
         text = "shape: SQUARE posn: upper left color: BLACK"
-        OneOrMore(attr_expr).parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
+        attr_expr[1, ...].parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
 
         # use stop_on attribute for OneOrMore to avoid reading label string as part of the data
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
@@ -4879,9 +4879,9 @@ class ZeroOrMore(_MultipleMatch):
     def __init__(
         self,
         expr: ParserElement,
-        stop_on: OptionalType[Union[ParserElement, str]] = None,
+        stop_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
-        stopOn: OptionalType[Union[ParserElement, str]] = None,
+        stopOn: typing.Optional[Union[ParserElement, str]] = None,
     ):
         super().__init__(expr, stopOn=stopOn or stop_on)
         self.mayReturnEmpty = True
@@ -5046,7 +5046,7 @@ class SkipTo(ParseElementEnhance):
         other: Union[ParserElement, str],
         include: bool = False,
         ignore: bool = None,
-        fail_on: OptionalType[Union[ParserElement, str]] = None,
+        fail_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
         failOn: Union[ParserElement, str] = None,
     ):
@@ -5143,7 +5143,7 @@ class Forward(ParseElementEnhance):
     parser created using ``Forward``.
     """
 
-    def __init__(self, other: OptionalType[Union[ParserElement, str]] = None):
+    def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None):
         self.caller_frame = traceback.extract_stack(limit=2)[0]
         super().__init__(other, savelist=False)
         self.lshift_line = None
@@ -5395,7 +5395,7 @@ class Combine(TokenConverter):
         join_string: str = "",
         adjacent: bool = True,
         *,
-        joinString: OptionalType[str] = None,
+        joinString: typing.Optional[str] = None,
     ):
         super().__init__(expr)
         joinString = joinString if joinString is not None else join_string
@@ -5482,10 +5482,10 @@ class Dict(TokenConverter):
         attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
 
         # print attributes as plain groups
-        print(OneOrMore(attr_expr).parse_string(text).dump())
+        print(attr_expr[1, ...].parse_string(text).dump())
 
-        # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names
-        result = Dict(OneOrMore(Group(attr_expr))).parse_string(text)
+        # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names
+        result = Dict(Group(attr_expr)[1, ...]).parse_string(text)
         print(result.dump())
 
         # access named fields as dict entries, or output as dict
@@ -5558,12 +5558,12 @@ class Suppress(TokenConverter):
 
         source = "a, b, c,d"
         wd = Word(alphas)
-        wd_list1 = wd + ZeroOrMore(',' + wd)
+        wd_list1 = wd + (',' + wd)[...]
         print(wd_list1.parse_string(source))
 
         # often, delimiters that are useful during parsing are just in the
         # way afterward - use Suppress to keep them out of the parsed output
-        wd_list2 = wd + ZeroOrMore(Suppress(',') + wd)
+        wd_list2 = wd + (Suppress(',') + wd)[...]
         print(wd_list2.parse_string(source))
 
         # Skipped text (using '...') can be suppressed as well
@@ -5622,7 +5622,7 @@ def trace_parse_action(f: ParseAction) -> ParseAction:
         def remove_duplicate_chars(tokens):
             return ''.join(sorted(set(''.join(tokens))))
 
-        wds = OneOrMore(wd).set_parse_action(remove_duplicate_chars)
+        wds = wd[1, ...].set_parse_action(remove_duplicate_chars)
         print(wds.parse_string("slkdjs sld sldd sdlf sdljf"))
 
     prints::
@@ -5728,18 +5728,18 @@ def token_map(func, *args) -> ParseAction:
 
     Example (compare the last to example in :class:`ParserElement.transform_string`::
 
-        hex_ints = OneOrMore(Word(hexnums)).set_parse_action(token_map(int, 16))
+        hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16))
         hex_ints.run_tests('''
             00 11 22 aa FF 0a 0d 1a
             ''')
 
         upperword = Word(alphas).set_parse_action(token_map(str.upper))
-        OneOrMore(upperword).run_tests('''
+        upperword[1, ...].run_tests('''
             my kingdom for a horse
             ''')
 
         wd = Word(alphas).set_parse_action(token_map(str.title))
-        OneOrMore(wd).set_parse_action(' '.join).run_tests('''
+        wd[1, ...].set_parse_action(' '.join).run_tests('''
             now is the winter of our discontent made glorious summer by this sun of york
             ''')
 
@@ -5795,7 +5795,9 @@ punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
 
 # build list of built-in expressions, for future reference if a global default value
 # gets updated
-_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)]
+_builtin_exprs: List[ParserElement] = [
+    v for v in vars().values() if isinstance(v, ParserElement)
+]
 
 # backward compatibility names
 tokenMap = token_map
index 2d0c587cbf42126eb903f27c11dc2dde9146c1cc..898644755cbbf9a8d4df562663114a7eb7e11fd1 100644 (file)
@@ -1,9 +1,8 @@
 import railroad
 import pyparsing
-from pkg_resources import resource_filename
+import typing
 from typing import (
     List,
-    Optional,
     NamedTuple,
     Generic,
     TypeVar,
@@ -17,13 +16,41 @@ from io import StringIO
 import inspect
 
 
-with open(resource_filename(__name__, "template.jinja2"), encoding="utf-8") as fp:
-    template = Template(fp.read())
+jinja2_template_source = """\
+<!DOCTYPE html>
+<html>
+<head>
+    {% if not head %}
+        <style type="text/css">
+            .railroad-heading {
+                font-family: monospace;
+            }
+        </style>
+    {% else %}
+        {{ head | safe }}
+    {% endif %}
+</head>
+<body>
+{{ body | safe }}
+{% for diagram in diagrams %}
+    <div class="railroad-group">
+        <h1 class="railroad-heading">{{ diagram.title }}</h1>
+        <div class="railroad-description">{{ diagram.text }}</div>
+        <div class="railroad-svg">
+            {{ diagram.svg }}
+        </div>
+    </div>
+{% endfor %}
+</body>
+</html>
+"""
+
+template = Template(jinja2_template_source)
 
 # Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet
 NamedDiagram = NamedTuple(
     "NamedDiagram",
-    [("name", str), ("diagram", Optional[railroad.DiagramItem]), ("index", int)],
+    [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)],
 )
 """
 A simple structure for associating a name with a railroad diagram
@@ -107,6 +134,8 @@ def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str:
     """
     data = []
     for diagram in diagrams:
+        if diagram.diagram is None:
+            continue
         io = StringIO()
         diagram.diagram.writeSvg(io.write)
         title = diagram.name
@@ -135,7 +164,7 @@ def resolve_partial(partial: "EditablePartial[T]") -> T:
 
 def to_railroad(
     element: pyparsing.ParserElement,
-    diagram_kwargs: Optional[dict] = None,
+    diagram_kwargs: typing.Optional[dict] = None,
     vertical: int = 3,
     show_results_names: bool = False,
     show_groups: bool = False,
@@ -216,12 +245,12 @@ class ElementState:
         parent: EditablePartial,
         number: int,
         name: str = None,
-        parent_index: Optional[int] = None,
+        parent_index: typing.Optional[int] = None,
     ):
         #: The pyparsing element that this represents
         self.element: pyparsing.ParserElement = element
         #: The name of the element
-        self.name: str = name
+        self.name: typing.Optional[str] = name
         #: The output Railroad element in an unconverted state
         self.converted: EditablePartial = converted
         #: The parent Railroad element, which we store so that we can extract this if it's duplicated
@@ -229,7 +258,7 @@ class ElementState:
         #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram
         self.number: int = number
         #: The index of this inside its parent
-        self.parent_index: Optional[int] = parent_index
+        self.parent_index: typing.Optional[int] = parent_index
         #: If true, we should extract this out into a subdiagram
         self.extract: bool = False
         #: If true, all of this element's children have been filled out
@@ -270,7 +299,7 @@ class ConverterState:
     Stores some state that persists between recursions into the element tree
     """
 
-    def __init__(self, diagram_kwargs: Optional[dict] = None):
+    def __init__(self, diagram_kwargs: typing.Optional[dict] = None):
         #: A dictionary mapping ParserElements to state relating to them
         self._element_diagram_states: Dict[int, ElementState] = {}
         #: A dictionary mapping ParserElement IDs to subdiagrams generated from them
@@ -361,14 +390,14 @@ def _apply_diagram_item_enhancements(fn):
 
     def _inner(
         element: pyparsing.ParserElement,
-        parent: Optional[EditablePartial],
+        parent: typing.Optional[EditablePartial],
         lookup: ConverterState = None,
         vertical: int = None,
         index: int = 0,
         name_hint: str = None,
         show_results_names: bool = False,
         show_groups: bool = False,
-    ) -> Optional[EditablePartial]:
+    ) -> typing.Optional[EditablePartial]:
 
         ret = fn(
             element,
@@ -412,14 +441,14 @@ def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]):
 @_apply_diagram_item_enhancements
 def _to_diagram_element(
     element: pyparsing.ParserElement,
-    parent: Optional[EditablePartial],
+    parent: typing.Optional[EditablePartial],
     lookup: ConverterState = None,
     vertical: int = None,
     index: int = 0,
     name_hint: str = None,
     show_results_names: bool = False,
     show_groups: bool = False,
-) -> Optional[EditablePartial]:
+) -> typing.Optional[EditablePartial]:
     """
     Recursively converts a PyParsing Element to a railroad Element
     :param lookup: The shared converter state that keeps track of useful things
@@ -526,7 +555,9 @@ def _to_diagram_element(
         else:
             ret = EditablePartial.from_call(railroad.Group, label="", item="")
     elif isinstance(element, pyparsing.TokenConverter):
-        ret = EditablePartial.from_call(AnnotatedItem, label=type(element).__name__.lower(), item="")
+        ret = EditablePartial.from_call(
+            AnnotatedItem, label=type(element).__name__.lower(), item=""
+        )
     elif isinstance(element, pyparsing.Opt):
         ret = EditablePartial.from_call(railroad.Optional, item="")
     elif isinstance(element, pyparsing.OneOrMore):
diff --git a/pkg_resources/_vendor/pyparsing/diagram/template.jinja2 b/pkg_resources/_vendor/pyparsing/diagram/template.jinja2
deleted file mode 100644 (file)
index d2219fb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    {% if not head %}
-        <style type="text/css">
-            .railroad-heading {
-                font-family: monospace;
-            }
-        </style>
-    {% else %}
-        {{ hear | safe }}
-    {% endif %}
-</head>
-<body>
-{{ body | safe }}
-{% for diagram in diagrams %}
-    <div class="railroad-group">
-        <h1 class="railroad-heading">{{ diagram.title }}</h1>
-        <div class="railroad-description">{{ diagram.text }}</div>
-        <div class="railroad-svg">
-            {{ diagram.svg }}
-        </div>
-    </div>
-{% endfor %}
-</body>
-</html>
index e06513eb00f723c3cb4efc4188141c2a6e303dd0..a38447bb05bd5d503a32651d6046ff8667785c0c 100644 (file)
@@ -2,7 +2,7 @@
 
 import re
 import sys
-from typing import Optional
+import typing
 
 from .util import col, line, lineno, _collapse_string_to_ranges
 from .unicode import pyparsing_unicode as ppu
@@ -25,7 +25,7 @@ class ParseBaseException(Exception):
         self,
         pstr: str,
         loc: int = 0,
-        msg: Optional[str] = None,
+        msg: typing.Optional[str] = None,
         elem=None,
     ):
         self.loc = loc
index be8a3657884806a8e7bf5e8e338b3fc86eeffa5b..9588b3b780159a2a2d23c7f84a4404ec350e2b65 100644 (file)
@@ -1,6 +1,7 @@
 # helpers.py
 import html.entities
 import re
+import typing
 
 from . import __diag__
 from .core import *
@@ -14,8 +15,8 @@ def delimited_list(
     expr: Union[str, ParserElement],
     delim: Union[str, ParserElement] = ",",
     combine: bool = False,
-    min: OptionalType[int] = None,
-    max: OptionalType[int] = None,
+    min: typing.Optional[int] = None,
+    max: typing.Optional[int] = None,
     *,
     allow_trailing_delim: bool = False,
 ) -> ParserElement:
@@ -69,9 +70,9 @@ def delimited_list(
 
 def counted_array(
     expr: ParserElement,
-    int_expr: OptionalType[ParserElement] = None,
+    int_expr: typing.Optional[ParserElement] = None,
     *,
-    intExpr: OptionalType[ParserElement] = None,
+    intExpr: typing.Optional[ParserElement] = None,
 ) -> ParserElement:
     """Helper to define a counted list of expressions.
 
@@ -197,7 +198,7 @@ def match_previous_expr(expr: ParserElement) -> ParserElement:
 
 
 def one_of(
-    strs: Union[IterableType[str], str],
+    strs: Union[typing.Iterable[str], str],
     caseless: bool = False,
     use_regex: bool = True,
     as_keyword: bool = False,
@@ -337,7 +338,7 @@ def dict_of(key: ParserElement, value: ParserElement) -> ParserElement:
 
         text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
         attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
-        print(OneOrMore(attr_expr).parse_string(text).dump())
+        print(attr_expr[1, ...].parse_string(text).dump())
 
         attr_label = label
         attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)
@@ -461,7 +462,7 @@ def locatedExpr(expr: ParserElement) -> ParserElement:
 def nested_expr(
     opener: Union[str, ParserElement] = "(",
     closer: Union[str, ParserElement] = ")",
-    content: OptionalType[ParserElement] = None,
+    content: typing.Optional[ParserElement] = None,
     ignore_expr: ParserElement = quoted_string(),
     *,
     ignoreExpr: ParserElement = quoted_string(),
@@ -682,6 +683,8 @@ def make_xml_tags(
     return _makeTags(tag_str, True)
 
 
+any_open_tag: ParserElement
+any_close_tag: ParserElement
 any_open_tag, any_close_tag = make_html_tags(
     Word(alphas, alphanums + "_:").set_name("any tag")
 )
@@ -710,7 +713,7 @@ InfixNotationOperatorSpec = Union[
         InfixNotationOperatorArgType,
         int,
         OpAssoc,
-        OptionalType[ParseAction],
+        typing.Optional[ParseAction],
     ],
     Tuple[
         InfixNotationOperatorArgType,
@@ -840,7 +843,7 @@ def infix_notation(
         if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT):
             raise ValueError("operator must indicate right or left associativity")
 
-        thisExpr = Forward().set_name(term_name)
+        thisExpr: Forward = Forward().set_name(term_name)
         if rightLeftAssoc is OpAssoc.LEFT:
             if arity == 1:
                 matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...])
@@ -945,7 +948,7 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]
         assignment = Group(identifier + "=" + rvalue)
         stmt << (funcDef | assignment | identifier)
 
-        module_body = OneOrMore(stmt)
+        module_body = stmt[1, ...]
 
         parseTree = module_body.parseString(data)
         parseTree.pprint()
@@ -1055,7 +1058,9 @@ python_style_comment = Regex(r"#.*").set_name("Python style comment")
 
 # build list of built-in expressions, for future reference if a global default value
 # gets updated
-_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)]
+_builtin_exprs: List[ParserElement] = [
+    v for v in vars().values() if isinstance(v, ParserElement)
+]
 
 
 # pre-PEP8 compatible names
index bb444df4e5b2405f97d480a73d86927fb3260620..00c9421d3b0362526b8f90dc01e8db73841e0b61 100644 (file)
@@ -287,7 +287,7 @@ class ParseResults:
             print(numlist.parse_string("0 123 321")) # -> ['123', '321']
 
             label = Word(alphas)
-            patt = label("LABEL") + OneOrMore(Word(nums))
+            patt = label("LABEL") + Word(nums)[1, ...]
             print(patt.parse_string("AAB 123 321").dump())
 
             # Use pop() in a parse action to remove named result (note that corresponding value is not
@@ -394,7 +394,7 @@ class ParseResults:
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
 
             # use a parse action to append the reverse of the matched strings, to make a palindrome
             def make_palindrome(tokens):
@@ -487,7 +487,7 @@ class ParseResults:
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
             result = patt.parse_string("sldkj lsdkj sldkj")
             # even though the result prints in string-like form, it is actually a pyparsing ParseResults
             print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj']
@@ -554,7 +554,7 @@ class ParseResults:
             user_data = (Group(house_number_expr)("house_number")
                         | Group(ssn_expr)("ssn")
                         | Group(integer)("age"))
-            user_info = OneOrMore(user_data)
+            user_info = user_data[1, ...]
 
             result = user_info.parse_string("22 111-22-3333 #221B")
             for item in result:
index 991972f3fb2986d2d03951be87b07eeb6bce77bc..84a0ef17078c99e5917db41e3dbaf035fe206d7c 100644 (file)
@@ -1,7 +1,7 @@
 # testing.py
 
 from contextlib import contextmanager
-from typing import Optional
+import typing
 
 from .core import (
     ParserElement,
@@ -237,12 +237,12 @@ class pyparsing_test:
     @staticmethod
     def with_line_numbers(
         s: str,
-        start_line: Optional[int] = None,
-        end_line: Optional[int] = None,
+        start_line: typing.Optional[int] = None,
+        end_line: typing.Optional[int] = None,
         expand_tabs: bool = True,
         eol_mark: str = "|",
-        mark_spaces: Optional[str] = None,
-        mark_control: Optional[str] = None,
+        mark_spaces: typing.Optional[str] = None,
+        mark_control: typing.Optional[str] = None,
     ) -> str:
         """
         Helpful method for debugging a parser - prints a string with line and column numbers.
index 92261487c7af50ede7204c4b65299f2ed333bed1..06526203911de55da3c2a8c5ae73f48024c3f018 100644 (file)
@@ -120,7 +120,18 @@ class pyparsing_unicode(unicode_set):
     A namespace class for defining common language unicode_sets.
     """
 
-    _ranges: UnicodeRangeList = [(32, sys.maxunicode)]
+    # fmt: off
+
+    # define ranges in language character sets
+    _ranges: UnicodeRangeList = [
+        (0x0020, sys.maxunicode),
+    ]
+
+    class BasicMultilingualPlane(unicode_set):
+        "Unicode set for the Basic Multilingual Plane"
+        _ranges: UnicodeRangeList = [
+            (0x0020, 0xFFFF),
+        ]
 
     class Latin1(unicode_set):
         "Unicode set for Latin-1 Unicode Character Range"
@@ -278,11 +289,13 @@ class pyparsing_unicode(unicode_set):
 
     class CJK(Chinese, Japanese, Hangul):
         "Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range"
-        pass
 
     class Thai(unicode_set):
         "Unicode set for Thai Unicode Character Range"
-        _ranges: UnicodeRangeList = [(0x0E01, 0x0E3A), (0x0E3F, 0x0E5B)]
+        _ranges: UnicodeRangeList = [
+            (0x0E01, 0x0E3A),
+            (0x0E3F, 0x0E5B)
+        ]
 
     class Arabic(unicode_set):
         "Unicode set for Arabic Unicode Character Range"
@@ -308,7 +321,12 @@ class pyparsing_unicode(unicode_set):
 
     class Devanagari(unicode_set):
         "Unicode set for Devanagari Unicode Character Range"
-        _ranges: UnicodeRangeList = [(0x0900, 0x097F), (0xA8E0, 0xA8FF)]
+        _ranges: UnicodeRangeList = [
+            (0x0900, 0x097F),
+            (0xA8E0, 0xA8FF)
+        ]
+
+    # fmt: on
 
 
 pyparsing_unicode.Japanese._ranges = (
@@ -317,7 +335,9 @@ pyparsing_unicode.Japanese._ranges = (
     + pyparsing_unicode.Japanese.Katakana._ranges
 )
 
-# define ranges in language character sets
+pyparsing_unicode.BMP = pyparsing_unicode.BasicMultilingualPlane
+
+# add language identifiers using language Unicode
 pyparsing_unicode.العربية = pyparsing_unicode.Arabic
 pyparsing_unicode.中文 = pyparsing_unicode.Chinese
 pyparsing_unicode.кириллица = pyparsing_unicode.Cyrillic
index 8f9c2639206722ca47c5767831733983b73a9848..8e015069a5927893df3c3652e4b5c31544716fc2 100644 (file)
@@ -1,5 +1,5 @@
 packaging==21.3
-pyparsing==3.0.8
+pyparsing==3.0.9
 appdirs==1.4.3
 jaraco.text==3.7.0
 # required for jaraco.text on older Pythons
index 5f6b9a54531ac4783bb6e8ace4b73d2ef3e3badb..ce714fb18b05b49f4431d5a87cf6721b53964087 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = setuptools
-version = 63.4.1
+version = 63.4.2
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
 description = Easily download, build, install, upgrade, and uninstall Python packages
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/INSTALLER b/setuptools/_vendor/pyparsing-3.0.8.dist-info/INSTALLER
deleted file mode 100644 (file)
index a1b589e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/LICENSE b/setuptools/_vendor/pyparsing-3.0.8.dist-info/LICENSE
deleted file mode 100644 (file)
index 1bf9852..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-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.
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/METADATA b/setuptools/_vendor/pyparsing-3.0.8.dist-info/METADATA
deleted file mode 100644 (file)
index d6c8e9b..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-Metadata-Version: 2.1
-Name: pyparsing
-Version: 3.0.8
-Summary: pyparsing module - Classes and methods to define and execute parsing grammars
-Author-email: Paul McGuire <ptmcg.gm+pyparsing@gmail.com>
-Requires-Python: >=3.6.8
-Description-Content-Type: text/x-rst
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: Information Technology
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Typing :: Typed
-Requires-Dist: railroad-diagrams ; extra == "diagrams"
-Requires-Dist: jinja2 ; extra == "diagrams"
-Project-URL: Homepage, https://github.com/pyparsing/pyparsing/
-Provides-Extra: diagrams
-
-PyParsing -- A Python Parsing Module
-====================================
-
-|Build Status| |Coverage|
-
-Introduction
-============
-
-The pyparsing module is an alternative approach to creating and
-executing simple grammars, vs. the traditional lex/yacc approach, or the
-use of regular expressions. The pyparsing module provides a library of
-classes that client code uses to construct the grammar directly in
-Python code.
-
-*[Since first writing this description of pyparsing in late 2003, this
-technique for developing parsers has become more widespread, under the
-name Parsing Expression Grammars - PEGs. See more information on PEGs*
-`here <https://en.wikipedia.org/wiki/Parsing_expression_grammar>`__
-*.]*
-
-Here is a program to parse ``"Hello, World!"`` (or any greeting of the form
-``"salutation, addressee!"``):
-
-.. code:: python
-
-    from pyparsing import Word, alphas
-    greet = Word(alphas) + "," + Word(alphas) + "!"
-    hello = "Hello, World!"
-    print(hello, "->", greet.parseString(hello))
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the
-self-explanatory class names, and the use of '+', '|' and '^' operator
-definitions.
-
-The parsed results returned from ``parseString()`` is a collection of type
-``ParseResults``, which can be accessed as a
-nested list, a dictionary, or an object with named attributes.
-
-The pyparsing module handles some of the problems that are typically
-vexing when writing text parsers:
-
-- extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.)
-- quoted strings
-- embedded comments
-
-The examples directory includes a simple SQL parser, simple CORBA IDL
-parser, a config file parser, a chemical formula parser, and a four-
-function algebraic notation parser, among many others.
-
-Documentation
-=============
-
-There are many examples in the online docstrings of the classes
-and methods in pyparsing. You can find them compiled into `online docs <https://pyparsing-docs.readthedocs.io/en/latest/>`__. Additional
-documentation resources and project info are listed in the online
-`GitHub wiki <https://github.com/pyparsing/pyparsing/wiki>`__. An
-entire directory of examples can be found `here <https://github.com/pyparsing/pyparsing/tree/master/examples>`__.
-
-License
-=======
-
-MIT License. See header of the `pyparsing.py <https://github.com/pyparsing/pyparsing/blob/master/pyparsing/__init__.py#L1-L23>`__ file.
-
-History
-=======
-
-See `CHANGES <https://github.com/pyparsing/pyparsing/blob/master/CHANGES>`__ file.
-
-.. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg
-   :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml
-.. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg
-  :target: https://codecov.io/gh/pyparsing/pyparsing
-
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/RECORD b/setuptools/_vendor/pyparsing-3.0.8.dist-info/RECORD
deleted file mode 100644 (file)
index 72947b0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-pyparsing-3.0.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pyparsing-3.0.8.dist-info/LICENSE,sha256=ENUSChaAWAT_2otojCIL-06POXQbVzIGBNRVowngGXI,1023
-pyparsing-3.0.8.dist-info/METADATA,sha256=dEvZBGz3Owm5LYEaqDeKb6e3ZgOrF48WaCI_PG1n5BE,4207
-pyparsing-3.0.8.dist-info/RECORD,,
-pyparsing-3.0.8.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pyparsing-3.0.8.dist-info/WHEEL,sha256=jPMR_Dzkc4X4icQtmz81lnNY_kAsfog7ry7qoRvYLXw,81
-pyparsing/__init__.py,sha256=EMa1HCuq9HJhEDR8fUThu2gD0nl6Cs8FFEWZZ0eRCM8,9159
-pyparsing/__pycache__/__init__.cpython-38.pyc,,
-pyparsing/__pycache__/actions.cpython-38.pyc,,
-pyparsing/__pycache__/common.cpython-38.pyc,,
-pyparsing/__pycache__/core.cpython-38.pyc,,
-pyparsing/__pycache__/exceptions.cpython-38.pyc,,
-pyparsing/__pycache__/helpers.cpython-38.pyc,,
-pyparsing/__pycache__/results.cpython-38.pyc,,
-pyparsing/__pycache__/testing.cpython-38.pyc,,
-pyparsing/__pycache__/unicode.cpython-38.pyc,,
-pyparsing/__pycache__/util.cpython-38.pyc,,
-pyparsing/actions.py,sha256=60v7mETOBzc01YPH_qQD5isavgcSJpAfIKpzgjM3vaU,6429
-pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936
-pyparsing/core.py,sha256=zBzGw5vcSd58pB1QkYpY6O_XCcHVKX_nH5xglRx_L-M,213278
-pyparsing/diagram/__init__.py,sha256=oU_UEh6O5voKSFjUdq462_mpmURLOfUIsmWvxi1qgTQ,23003
-pyparsing/diagram/__pycache__/__init__.cpython-38.pyc,,
-pyparsing/diagram/template.jinja2,sha256=SfQ8SLktSBqI5W1DGcUVH1vdflRD6x2sQBApxrcNg7s,589
-pyparsing/exceptions.py,sha256=H4D9gqMavqmAFSsdrU_J6bO-jA-T-A7yvtXWZpooIUA,9030
-pyparsing/helpers.py,sha256=EyjpgDOc3ivwRsU4VXxAWdgIs5gaqMDaLWcwRh5mqxc,39007
-pyparsing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pyparsing/results.py,sha256=Hd6FAAh5sF8zGXpwsamdVqFUblIwyQf0FH0t7FCb1OY,25353
-pyparsing/testing.py,sha256=szs8AKZREZMhL0y0vsMfaTVAnpqPHetg6VKJBNmc4QY,13388
-pyparsing/unicode.py,sha256=IR-ioeGY29cZ49tG8Ts7ITPWWNP5G2DcZs58oa8zn44,10381
-pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/REQUESTED b/setuptools/_vendor/pyparsing-3.0.8.dist-info/REQUESTED
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/setuptools/_vendor/pyparsing-3.0.8.dist-info/WHEEL b/setuptools/_vendor/pyparsing-3.0.8.dist-info/WHEEL
deleted file mode 100644 (file)
index c727d14..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: flit 3.6.0
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/INSTALLER b/setuptools/_vendor/pyparsing-3.0.9.dist-info/INSTALLER
new file mode 100644 (file)
index 0000000..a1b589e
--- /dev/null
@@ -0,0 +1 @@
+pip
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/LICENSE b/setuptools/_vendor/pyparsing-3.0.9.dist-info/LICENSE
new file mode 100644 (file)
index 0000000..1bf9852
--- /dev/null
@@ -0,0 +1,18 @@
+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.
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/METADATA b/setuptools/_vendor/pyparsing-3.0.9.dist-info/METADATA
new file mode 100644 (file)
index 0000000..33e5194
--- /dev/null
@@ -0,0 +1,105 @@
+Metadata-Version: 2.1
+Name: pyparsing
+Version: 3.0.9
+Summary: pyparsing module - Classes and methods to define and execute parsing grammars
+Author-email: Paul McGuire <ptmcg.gm+pyparsing@gmail.com>
+Requires-Python: >=3.6.8
+Description-Content-Type: text/x-rst
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Typing :: Typed
+Requires-Dist: railroad-diagrams ; extra == "diagrams"
+Requires-Dist: jinja2 ; extra == "diagrams"
+Project-URL: Homepage, https://github.com/pyparsing/pyparsing/
+Provides-Extra: diagrams
+
+PyParsing -- A Python Parsing Module
+====================================
+
+|Build Status| |Coverage|
+
+Introduction
+============
+
+The pyparsing module is an alternative approach to creating and
+executing simple grammars, vs. the traditional lex/yacc approach, or the
+use of regular expressions. The pyparsing module provides a library of
+classes that client code uses to construct the grammar directly in
+Python code.
+
+*[Since first writing this description of pyparsing in late 2003, this
+technique for developing parsers has become more widespread, under the
+name Parsing Expression Grammars - PEGs. See more information on PEGs*
+`here <https://en.wikipedia.org/wiki/Parsing_expression_grammar>`__
+*.]*
+
+Here is a program to parse ``"Hello, World!"`` (or any greeting of the form
+``"salutation, addressee!"``):
+
+.. code:: python
+
+    from pyparsing import Word, alphas
+    greet = Word(alphas) + "," + Word(alphas) + "!"
+    hello = "Hello, World!"
+    print(hello, "->", greet.parseString(hello))
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the
+self-explanatory class names, and the use of '+', '|' and '^' operator
+definitions.
+
+The parsed results returned from ``parseString()`` is a collection of type
+``ParseResults``, which can be accessed as a
+nested list, a dictionary, or an object with named attributes.
+
+The pyparsing module handles some of the problems that are typically
+vexing when writing text parsers:
+
+- extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.)
+- quoted strings
+- embedded comments
+
+The examples directory includes a simple SQL parser, simple CORBA IDL
+parser, a config file parser, a chemical formula parser, and a four-
+function algebraic notation parser, among many others.
+
+Documentation
+=============
+
+There are many examples in the online docstrings of the classes
+and methods in pyparsing. You can find them compiled into `online docs <https://pyparsing-docs.readthedocs.io/en/latest/>`__. Additional
+documentation resources and project info are listed in the online
+`GitHub wiki <https://github.com/pyparsing/pyparsing/wiki>`__. An
+entire directory of examples can be found `here <https://github.com/pyparsing/pyparsing/tree/master/examples>`__.
+
+License
+=======
+
+MIT License. See header of the `pyparsing.py <https://github.com/pyparsing/pyparsing/blob/master/pyparsing/__init__.py#L1-L23>`__ file.
+
+History
+=======
+
+See `CHANGES <https://github.com/pyparsing/pyparsing/blob/master/CHANGES>`__ file.
+
+.. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg
+   :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml
+.. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg
+  :target: https://codecov.io/gh/pyparsing/pyparsing
+
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/RECORD b/setuptools/_vendor/pyparsing-3.0.9.dist-info/RECORD
new file mode 100644 (file)
index 0000000..7a4e49a
--- /dev/null
@@ -0,0 +1,29 @@
+pyparsing-3.0.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+pyparsing-3.0.9.dist-info/LICENSE,sha256=ENUSChaAWAT_2otojCIL-06POXQbVzIGBNRVowngGXI,1023
+pyparsing-3.0.9.dist-info/METADATA,sha256=h_fpm9rwvgZsE8v5YNF4IAo-IpaFWCOfUEm5MMByIiM,4207
+pyparsing-3.0.9.dist-info/RECORD,,
+pyparsing-3.0.9.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pyparsing-3.0.9.dist-info/WHEEL,sha256=jPMR_Dzkc4X4icQtmz81lnNY_kAsfog7ry7qoRvYLXw,81
+pyparsing/__init__.py,sha256=52QH3lgPbJhba0estckoGPHRH8JvQSSCGoWiEn2m0bU,9159
+pyparsing/__pycache__/__init__.cpython-38.pyc,,
+pyparsing/__pycache__/actions.cpython-38.pyc,,
+pyparsing/__pycache__/common.cpython-38.pyc,,
+pyparsing/__pycache__/core.cpython-38.pyc,,
+pyparsing/__pycache__/exceptions.cpython-38.pyc,,
+pyparsing/__pycache__/helpers.cpython-38.pyc,,
+pyparsing/__pycache__/results.cpython-38.pyc,,
+pyparsing/__pycache__/testing.cpython-38.pyc,,
+pyparsing/__pycache__/unicode.cpython-38.pyc,,
+pyparsing/__pycache__/util.cpython-38.pyc,,
+pyparsing/actions.py,sha256=wU9i32e0y1ymxKE3OUwSHO-SFIrt1h_wv6Ws0GQjpNU,6426
+pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936
+pyparsing/core.py,sha256=u8GptQE_H6wMkl8OZhxeK1aAPIDXXNgwdShORBwBVS4,213310
+pyparsing/diagram/__init__.py,sha256=f_EfxahqrdkRVahmTwLJXkZ9EEDKNd-O7lBbpJYlE1g,23668
+pyparsing/diagram/__pycache__/__init__.cpython-38.pyc,,
+pyparsing/exceptions.py,sha256=3LbSafD32NYb1Tzt85GHNkhEAU1eZkTtNSk24cPMemo,9023
+pyparsing/helpers.py,sha256=QpUOjW0-psvueMwWb9bQpU2noqKCv98_wnw1VSzSdVo,39129
+pyparsing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pyparsing/results.py,sha256=HgNvWVXBdQP-Q6PtJfoCEeOJk2nwEvG-2KVKC5sGA30,25341
+pyparsing/testing.py,sha256=7tu4Abp4uSeJV0N_yEPRmmNUhpd18ZQP3CrX41DM814,13402
+pyparsing/unicode.py,sha256=fwuhMj30SQ165Cv7HJpu-rSxGbRm93kN9L4Ei7VGc1Y,10787
+pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/REQUESTED b/setuptools/_vendor/pyparsing-3.0.9.dist-info/REQUESTED
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/setuptools/_vendor/pyparsing-3.0.9.dist-info/WHEEL b/setuptools/_vendor/pyparsing-3.0.9.dist-info/WHEEL
new file mode 100644 (file)
index 0000000..c727d14
--- /dev/null
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: flit 3.6.0
+Root-Is-Purelib: true
+Tag: py3-none-any
index 45f334d043fc72a77eef992cb4b2508f53837e2e..7802ff158d83eb88e6dbe78d9cd33ca14341662a 100644 (file)
@@ -128,8 +128,8 @@ class version_info(NamedTuple):
         )
 
 
-__version_info__ = version_info(3, 0, 8, "final", 0)
-__version_time__ = "09 Apr 2022 23:29 UTC"
+__version_info__ = version_info(3, 0, 9, "final", 0)
+__version_time__ = "05 May 2022 07:02 UTC"
 __version__ = __version_info__.__version__
 __versionTime__ = __version_time__
 __author__ = "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>"
index 2bcc5502b075ff39be828a05f9bdc2ea3e574cf0..f72c66e743146c7a5b70a5440e9ab5459f10245b 100644 (file)
@@ -55,7 +55,7 @@ def replace_with(repl_str):
         na = one_of("N/A NA").set_parse_action(replace_with(math.nan))
         term = na | num
 
-        OneOrMore(term).parse_string("324 234 N/A 234") # -> [324, 234, nan, 234]
+        term[1, ...].parse_string("324 234 N/A 234") # -> [324, 234, nan, 234]
     """
     return lambda s, l, t: [repl_str]
 
index 454bd57d0419439944b455c9c06958a97e7c8925..9acba3f3e984b404f52702964805732f03965048 100644 (file)
@@ -2,9 +2,8 @@
 # core.py
 #
 import os
+import typing
 from typing import (
-    Optional as OptionalType,
-    Iterable as IterableType,
     NamedTuple,
     Union,
     Callable,
@@ -14,7 +13,6 @@ from typing import (
     List,
     TextIO,
     Set,
-    Dict as DictType,
     Sequence,
 )
 from abc import ABC, abstractmethod
@@ -192,7 +190,7 @@ del __config_flags
 
 
 def _should_enable_warnings(
-    cmd_line_warn_options: IterableType[str], warn_env_var: OptionalType[str]
+    cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str]
 ) -> bool:
     enable = bool(warn_env_var)
     for warn_opt in cmd_line_warn_options:
@@ -404,7 +402,7 @@ class ParserElement(ABC):
 
     DEFAULT_WHITE_CHARS: str = " \n\t\r"
     verbose_stacktrace: bool = False
-    _literalStringClass: OptionalType[type] = None
+    _literalStringClass: typing.Optional[type] = None
 
     @staticmethod
     def set_default_whitespace_chars(chars: str) -> None:
@@ -414,11 +412,11 @@ class ParserElement(ABC):
         Example::
 
             # default whitespace chars are space, <TAB> and newline
-            OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
+            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
 
             # change to just treat newline as significant
             ParserElement.set_default_whitespace_chars(" \t")
-            OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
+            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
         """
         ParserElement.DEFAULT_WHITE_CHARS = chars
 
@@ -450,13 +448,13 @@ class ParserElement(ABC):
         ParserElement._literalStringClass = cls
 
     class DebugActions(NamedTuple):
-        debug_try: OptionalType[DebugStartAction]
-        debug_match: OptionalType[DebugSuccessAction]
-        debug_fail: OptionalType[DebugExceptionAction]
+        debug_try: typing.Optional[DebugStartAction]
+        debug_match: typing.Optional[DebugSuccessAction]
+        debug_fail: typing.Optional[DebugExceptionAction]
 
     def __init__(self, savelist: bool = False):
         self.parseAction: List[ParseAction] = list()
-        self.failAction: OptionalType[ParseFailAction] = None
+        self.failAction: typing.Optional[ParseFailAction] = None
         self.customName = None
         self._defaultName = None
         self.resultsName = None
@@ -510,7 +508,7 @@ class ParserElement(ABC):
             integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K")
             integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
 
-            print(OneOrMore(integerK | integerM | integer).parse_string("5K 100 640K 256M"))
+            print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M"))
 
         prints::
 
@@ -895,7 +893,7 @@ class ParserElement(ABC):
 
     # cache for left-recursion in Forward references
     recursion_lock = RLock()
-    recursion_memos: DictType[
+    recursion_memos: typing.Dict[
         Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]]
     ] = {}
 
@@ -985,7 +983,7 @@ class ParserElement(ABC):
 
     @staticmethod
     def enable_left_recursion(
-        cache_size_limit: OptionalType[int] = None, *, force=False
+        cache_size_limit: typing.Optional[int] = None, *, force=False
     ) -> None:
         """
         Enables "bounded recursion" parsing, which allows for both direct and indirect
@@ -1738,7 +1736,7 @@ class ParserElement(ABC):
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
             patt.parse_string('ablaj /* comment */ lskjd')
             # -> ['ablaj']
 
@@ -1798,7 +1796,7 @@ class ParserElement(ABC):
             # turn on debugging for wd
             wd.set_debug()
 
-            OneOrMore(term).parse_string("abc 123 xyz 890")
+            term[1, ...].parse_string("abc 123 xyz 890")
 
         prints::
 
@@ -1953,12 +1951,12 @@ class ParserElement(ABC):
         self,
         tests: Union[str, List[str]],
         parse_all: bool = True,
-        comment: OptionalType[Union["ParserElement", str]] = "#",
+        comment: typing.Optional[Union["ParserElement", str]] = "#",
         full_dump: bool = True,
         print_results: bool = True,
         failure_tests: bool = False,
         post_parse: Callable[[str, ParseResults], str] = None,
-        file: OptionalType[TextIO] = None,
+        file: typing.Optional[TextIO] = None,
         with_line_numbers: bool = False,
         *,
         parseAll: bool = True,
@@ -2385,11 +2383,11 @@ class Keyword(Token):
     def __init__(
         self,
         match_string: str = "",
-        ident_chars: OptionalType[str] = None,
+        ident_chars: typing.Optional[str] = None,
         caseless: bool = False,
         *,
         matchString: str = "",
-        identChars: OptionalType[str] = None,
+        identChars: typing.Optional[str] = None,
     ):
         super().__init__()
         identChars = identChars or ident_chars
@@ -2479,7 +2477,7 @@ class CaselessLiteral(Literal):
 
     Example::
 
-        OneOrMore(CaselessLiteral("CMD")).parse_string("cmd CMD Cmd10")
+        CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10")
         # -> ['CMD', 'CMD', 'CMD']
 
     (Contrast with example for :class:`CaselessKeyword`.)
@@ -2504,7 +2502,7 @@ class CaselessKeyword(Keyword):
 
     Example::
 
-        OneOrMore(CaselessKeyword("CMD")).parse_string("cmd CMD Cmd10")
+        CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10")
         # -> ['CMD', 'CMD']
 
     (Contrast with example for :class:`CaselessLiteral`.)
@@ -2513,10 +2511,10 @@ class CaselessKeyword(Keyword):
     def __init__(
         self,
         match_string: str = "",
-        ident_chars: OptionalType[str] = None,
+        ident_chars: typing.Optional[str] = None,
         *,
         matchString: str = "",
-        identChars: OptionalType[str] = None,
+        identChars: typing.Optional[str] = None,
     ):
         identChars = identChars or ident_chars
         match_string = matchString or match_string
@@ -2680,17 +2678,17 @@ class Word(Token):
     def __init__(
         self,
         init_chars: str = "",
-        body_chars: OptionalType[str] = None,
+        body_chars: typing.Optional[str] = None,
         min: int = 1,
         max: int = 0,
         exact: int = 0,
         as_keyword: bool = False,
-        exclude_chars: OptionalType[str] = None,
+        exclude_chars: typing.Optional[str] = None,
         *,
-        initChars: OptionalType[str] = None,
-        bodyChars: OptionalType[str] = None,
+        initChars: typing.Optional[str] = None,
+        bodyChars: typing.Optional[str] = None,
         asKeyword: bool = False,
-        excludeChars: OptionalType[str] = None,
+        excludeChars: typing.Optional[str] = None,
     ):
         initChars = initChars or init_chars
         bodyChars = bodyChars or body_chars
@@ -2872,10 +2870,10 @@ class Char(_WordRegex):
         self,
         charset: str,
         as_keyword: bool = False,
-        exclude_chars: OptionalType[str] = None,
+        exclude_chars: typing.Optional[str] = None,
         *,
         asKeyword: bool = False,
-        excludeChars: OptionalType[str] = None,
+        excludeChars: typing.Optional[str] = None,
     ):
         asKeyword = asKeyword or as_keyword
         excludeChars = excludeChars or exclude_chars
@@ -3088,18 +3086,18 @@ class QuotedString(Token):
     def __init__(
         self,
         quote_char: str = "",
-        esc_char: OptionalType[str] = None,
-        esc_quote: OptionalType[str] = None,
+        esc_char: typing.Optional[str] = None,
+        esc_quote: typing.Optional[str] = None,
         multiline: bool = False,
         unquote_results: bool = True,
-        end_quote_char: OptionalType[str] = None,
+        end_quote_char: typing.Optional[str] = None,
         convert_whitespace_escapes: bool = True,
         *,
         quoteChar: str = "",
-        escChar: OptionalType[str] = None,
-        escQuote: OptionalType[str] = None,
+        escChar: typing.Optional[str] = None,
+        escQuote: typing.Optional[str] = None,
         unquoteResults: bool = True,
-        endQuoteChar: OptionalType[str] = None,
+        endQuoteChar: typing.Optional[str] = None,
         convertWhitespaceEscapes: bool = True,
     ):
         super().__init__()
@@ -3600,7 +3598,7 @@ class ParseExpression(ParserElement):
     post-processing parsed tokens.
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(savelist)
         self.exprs: List[ParserElement]
         if isinstance(exprs, _generatorType):
@@ -3767,7 +3765,7 @@ class And(ParseExpression):
     Example::
 
         integer = Word(nums)
-        name_expr = OneOrMore(Word(alphas))
+        name_expr = Word(alphas)[1, ...]
 
         expr = And([integer("id"), name_expr("name"), integer("age")])
         # more easily written as:
@@ -3782,7 +3780,9 @@ class And(ParseExpression):
         def _generateDefaultName(self):
             return "-"
 
-    def __init__(self, exprs_arg: IterableType[ParserElement], savelist: bool = True):
+    def __init__(
+        self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True
+    ):
         exprs: List[ParserElement] = list(exprs_arg)
         if exprs and Ellipsis in exprs:
             tmp = []
@@ -3926,7 +3926,7 @@ class Or(ParseExpression):
         [['123'], ['3.1416'], ['789']]
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
@@ -4081,7 +4081,7 @@ class MatchFirst(ParseExpression):
         print(number.search_string("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
@@ -4232,7 +4232,7 @@ class Each(ParseExpression):
         - size: 20
     """
 
-    def __init__(self, exprs: IterableType[ParserElement], savelist: bool = True):
+    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True):
         super().__init__(exprs, savelist)
         if self.exprs:
             self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
@@ -4568,7 +4568,7 @@ class FollowedBy(ParseElementEnhance):
         label = data_word + FollowedBy(':')
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
 
-        OneOrMore(attr_expr).parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()
+        attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()
 
     prints::
 
@@ -4619,7 +4619,7 @@ class PrecededBy(ParseElementEnhance):
     """
 
     def __init__(
-        self, expr: Union[ParserElement, str], retreat: OptionalType[int] = None
+        self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None
     ):
         super().__init__(expr)
         self.expr = self.expr().leave_whitespace()
@@ -4730,7 +4730,7 @@ class NotAny(ParseElementEnhance):
 
         # very crude boolean expression - to support parenthesis groups and
         # operation hierarchy, use infix_notation
-        boolean_expr = boolean_term + ZeroOrMore((AND | OR) + boolean_term)
+        boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...]
 
         # integers that are followed by "." are actually floats
         integer = Word(nums) + ~Char(".")
@@ -4758,9 +4758,9 @@ class _MultipleMatch(ParseElementEnhance):
     def __init__(
         self,
         expr: ParserElement,
-        stop_on: OptionalType[Union[ParserElement, str]] = None,
+        stop_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
-        stopOn: OptionalType[Union[ParserElement, str]] = None,
+        stopOn: typing.Optional[Union[ParserElement, str]] = None,
     ):
         super().__init__(expr)
         stopOn = stopOn or stop_on
@@ -4849,7 +4849,7 @@ class OneOrMore(_MultipleMatch):
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join))
 
         text = "shape: SQUARE posn: upper left color: BLACK"
-        OneOrMore(attr_expr).parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
+        attr_expr[1, ...].parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
 
         # use stop_on attribute for OneOrMore to avoid reading label string as part of the data
         attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
@@ -4879,9 +4879,9 @@ class ZeroOrMore(_MultipleMatch):
     def __init__(
         self,
         expr: ParserElement,
-        stop_on: OptionalType[Union[ParserElement, str]] = None,
+        stop_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
-        stopOn: OptionalType[Union[ParserElement, str]] = None,
+        stopOn: typing.Optional[Union[ParserElement, str]] = None,
     ):
         super().__init__(expr, stopOn=stopOn or stop_on)
         self.mayReturnEmpty = True
@@ -5046,7 +5046,7 @@ class SkipTo(ParseElementEnhance):
         other: Union[ParserElement, str],
         include: bool = False,
         ignore: bool = None,
-        fail_on: OptionalType[Union[ParserElement, str]] = None,
+        fail_on: typing.Optional[Union[ParserElement, str]] = None,
         *,
         failOn: Union[ParserElement, str] = None,
     ):
@@ -5143,7 +5143,7 @@ class Forward(ParseElementEnhance):
     parser created using ``Forward``.
     """
 
-    def __init__(self, other: OptionalType[Union[ParserElement, str]] = None):
+    def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None):
         self.caller_frame = traceback.extract_stack(limit=2)[0]
         super().__init__(other, savelist=False)
         self.lshift_line = None
@@ -5395,7 +5395,7 @@ class Combine(TokenConverter):
         join_string: str = "",
         adjacent: bool = True,
         *,
-        joinString: OptionalType[str] = None,
+        joinString: typing.Optional[str] = None,
     ):
         super().__init__(expr)
         joinString = joinString if joinString is not None else join_string
@@ -5482,10 +5482,10 @@ class Dict(TokenConverter):
         attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
 
         # print attributes as plain groups
-        print(OneOrMore(attr_expr).parse_string(text).dump())
+        print(attr_expr[1, ...].parse_string(text).dump())
 
-        # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names
-        result = Dict(OneOrMore(Group(attr_expr))).parse_string(text)
+        # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names
+        result = Dict(Group(attr_expr)[1, ...]).parse_string(text)
         print(result.dump())
 
         # access named fields as dict entries, or output as dict
@@ -5558,12 +5558,12 @@ class Suppress(TokenConverter):
 
         source = "a, b, c,d"
         wd = Word(alphas)
-        wd_list1 = wd + ZeroOrMore(',' + wd)
+        wd_list1 = wd + (',' + wd)[...]
         print(wd_list1.parse_string(source))
 
         # often, delimiters that are useful during parsing are just in the
         # way afterward - use Suppress to keep them out of the parsed output
-        wd_list2 = wd + ZeroOrMore(Suppress(',') + wd)
+        wd_list2 = wd + (Suppress(',') + wd)[...]
         print(wd_list2.parse_string(source))
 
         # Skipped text (using '...') can be suppressed as well
@@ -5622,7 +5622,7 @@ def trace_parse_action(f: ParseAction) -> ParseAction:
         def remove_duplicate_chars(tokens):
             return ''.join(sorted(set(''.join(tokens))))
 
-        wds = OneOrMore(wd).set_parse_action(remove_duplicate_chars)
+        wds = wd[1, ...].set_parse_action(remove_duplicate_chars)
         print(wds.parse_string("slkdjs sld sldd sdlf sdljf"))
 
     prints::
@@ -5728,18 +5728,18 @@ def token_map(func, *args) -> ParseAction:
 
     Example (compare the last to example in :class:`ParserElement.transform_string`::
 
-        hex_ints = OneOrMore(Word(hexnums)).set_parse_action(token_map(int, 16))
+        hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16))
         hex_ints.run_tests('''
             00 11 22 aa FF 0a 0d 1a
             ''')
 
         upperword = Word(alphas).set_parse_action(token_map(str.upper))
-        OneOrMore(upperword).run_tests('''
+        upperword[1, ...].run_tests('''
             my kingdom for a horse
             ''')
 
         wd = Word(alphas).set_parse_action(token_map(str.title))
-        OneOrMore(wd).set_parse_action(' '.join).run_tests('''
+        wd[1, ...].set_parse_action(' '.join).run_tests('''
             now is the winter of our discontent made glorious summer by this sun of york
             ''')
 
@@ -5795,7 +5795,9 @@ punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
 
 # build list of built-in expressions, for future reference if a global default value
 # gets updated
-_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)]
+_builtin_exprs: List[ParserElement] = [
+    v for v in vars().values() if isinstance(v, ParserElement)
+]
 
 # backward compatibility names
 tokenMap = token_map
index 2d0c587cbf42126eb903f27c11dc2dde9146c1cc..898644755cbbf9a8d4df562663114a7eb7e11fd1 100644 (file)
@@ -1,9 +1,8 @@
 import railroad
 import pyparsing
-from pkg_resources import resource_filename
+import typing
 from typing import (
     List,
-    Optional,
     NamedTuple,
     Generic,
     TypeVar,
@@ -17,13 +16,41 @@ from io import StringIO
 import inspect
 
 
-with open(resource_filename(__name__, "template.jinja2"), encoding="utf-8") as fp:
-    template = Template(fp.read())
+jinja2_template_source = """\
+<!DOCTYPE html>
+<html>
+<head>
+    {% if not head %}
+        <style type="text/css">
+            .railroad-heading {
+                font-family: monospace;
+            }
+        </style>
+    {% else %}
+        {{ head | safe }}
+    {% endif %}
+</head>
+<body>
+{{ body | safe }}
+{% for diagram in diagrams %}
+    <div class="railroad-group">
+        <h1 class="railroad-heading">{{ diagram.title }}</h1>
+        <div class="railroad-description">{{ diagram.text }}</div>
+        <div class="railroad-svg">
+            {{ diagram.svg }}
+        </div>
+    </div>
+{% endfor %}
+</body>
+</html>
+"""
+
+template = Template(jinja2_template_source)
 
 # Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet
 NamedDiagram = NamedTuple(
     "NamedDiagram",
-    [("name", str), ("diagram", Optional[railroad.DiagramItem]), ("index", int)],
+    [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)],
 )
 """
 A simple structure for associating a name with a railroad diagram
@@ -107,6 +134,8 @@ def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str:
     """
     data = []
     for diagram in diagrams:
+        if diagram.diagram is None:
+            continue
         io = StringIO()
         diagram.diagram.writeSvg(io.write)
         title = diagram.name
@@ -135,7 +164,7 @@ def resolve_partial(partial: "EditablePartial[T]") -> T:
 
 def to_railroad(
     element: pyparsing.ParserElement,
-    diagram_kwargs: Optional[dict] = None,
+    diagram_kwargs: typing.Optional[dict] = None,
     vertical: int = 3,
     show_results_names: bool = False,
     show_groups: bool = False,
@@ -216,12 +245,12 @@ class ElementState:
         parent: EditablePartial,
         number: int,
         name: str = None,
-        parent_index: Optional[int] = None,
+        parent_index: typing.Optional[int] = None,
     ):
         #: The pyparsing element that this represents
         self.element: pyparsing.ParserElement = element
         #: The name of the element
-        self.name: str = name
+        self.name: typing.Optional[str] = name
         #: The output Railroad element in an unconverted state
         self.converted: EditablePartial = converted
         #: The parent Railroad element, which we store so that we can extract this if it's duplicated
@@ -229,7 +258,7 @@ class ElementState:
         #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram
         self.number: int = number
         #: The index of this inside its parent
-        self.parent_index: Optional[int] = parent_index
+        self.parent_index: typing.Optional[int] = parent_index
         #: If true, we should extract this out into a subdiagram
         self.extract: bool = False
         #: If true, all of this element's children have been filled out
@@ -270,7 +299,7 @@ class ConverterState:
     Stores some state that persists between recursions into the element tree
     """
 
-    def __init__(self, diagram_kwargs: Optional[dict] = None):
+    def __init__(self, diagram_kwargs: typing.Optional[dict] = None):
         #: A dictionary mapping ParserElements to state relating to them
         self._element_diagram_states: Dict[int, ElementState] = {}
         #: A dictionary mapping ParserElement IDs to subdiagrams generated from them
@@ -361,14 +390,14 @@ def _apply_diagram_item_enhancements(fn):
 
     def _inner(
         element: pyparsing.ParserElement,
-        parent: Optional[EditablePartial],
+        parent: typing.Optional[EditablePartial],
         lookup: ConverterState = None,
         vertical: int = None,
         index: int = 0,
         name_hint: str = None,
         show_results_names: bool = False,
         show_groups: bool = False,
-    ) -> Optional[EditablePartial]:
+    ) -> typing.Optional[EditablePartial]:
 
         ret = fn(
             element,
@@ -412,14 +441,14 @@ def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]):
 @_apply_diagram_item_enhancements
 def _to_diagram_element(
     element: pyparsing.ParserElement,
-    parent: Optional[EditablePartial],
+    parent: typing.Optional[EditablePartial],
     lookup: ConverterState = None,
     vertical: int = None,
     index: int = 0,
     name_hint: str = None,
     show_results_names: bool = False,
     show_groups: bool = False,
-) -> Optional[EditablePartial]:
+) -> typing.Optional[EditablePartial]:
     """
     Recursively converts a PyParsing Element to a railroad Element
     :param lookup: The shared converter state that keeps track of useful things
@@ -526,7 +555,9 @@ def _to_diagram_element(
         else:
             ret = EditablePartial.from_call(railroad.Group, label="", item="")
     elif isinstance(element, pyparsing.TokenConverter):
-        ret = EditablePartial.from_call(AnnotatedItem, label=type(element).__name__.lower(), item="")
+        ret = EditablePartial.from_call(
+            AnnotatedItem, label=type(element).__name__.lower(), item=""
+        )
     elif isinstance(element, pyparsing.Opt):
         ret = EditablePartial.from_call(railroad.Optional, item="")
     elif isinstance(element, pyparsing.OneOrMore):
diff --git a/setuptools/_vendor/pyparsing/diagram/template.jinja2 b/setuptools/_vendor/pyparsing/diagram/template.jinja2
deleted file mode 100644 (file)
index d2219fb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    {% if not head %}
-        <style type="text/css">
-            .railroad-heading {
-                font-family: monospace;
-            }
-        </style>
-    {% else %}
-        {{ hear | safe }}
-    {% endif %}
-</head>
-<body>
-{{ body | safe }}
-{% for diagram in diagrams %}
-    <div class="railroad-group">
-        <h1 class="railroad-heading">{{ diagram.title }}</h1>
-        <div class="railroad-description">{{ diagram.text }}</div>
-        <div class="railroad-svg">
-            {{ diagram.svg }}
-        </div>
-    </div>
-{% endfor %}
-</body>
-</html>
index e06513eb00f723c3cb4efc4188141c2a6e303dd0..a38447bb05bd5d503a32651d6046ff8667785c0c 100644 (file)
@@ -2,7 +2,7 @@
 
 import re
 import sys
-from typing import Optional
+import typing
 
 from .util import col, line, lineno, _collapse_string_to_ranges
 from .unicode import pyparsing_unicode as ppu
@@ -25,7 +25,7 @@ class ParseBaseException(Exception):
         self,
         pstr: str,
         loc: int = 0,
-        msg: Optional[str] = None,
+        msg: typing.Optional[str] = None,
         elem=None,
     ):
         self.loc = loc
index be8a3657884806a8e7bf5e8e338b3fc86eeffa5b..9588b3b780159a2a2d23c7f84a4404ec350e2b65 100644 (file)
@@ -1,6 +1,7 @@
 # helpers.py
 import html.entities
 import re
+import typing
 
 from . import __diag__
 from .core import *
@@ -14,8 +15,8 @@ def delimited_list(
     expr: Union[str, ParserElement],
     delim: Union[str, ParserElement] = ",",
     combine: bool = False,
-    min: OptionalType[int] = None,
-    max: OptionalType[int] = None,
+    min: typing.Optional[int] = None,
+    max: typing.Optional[int] = None,
     *,
     allow_trailing_delim: bool = False,
 ) -> ParserElement:
@@ -69,9 +70,9 @@ def delimited_list(
 
 def counted_array(
     expr: ParserElement,
-    int_expr: OptionalType[ParserElement] = None,
+    int_expr: typing.Optional[ParserElement] = None,
     *,
-    intExpr: OptionalType[ParserElement] = None,
+    intExpr: typing.Optional[ParserElement] = None,
 ) -> ParserElement:
     """Helper to define a counted list of expressions.
 
@@ -197,7 +198,7 @@ def match_previous_expr(expr: ParserElement) -> ParserElement:
 
 
 def one_of(
-    strs: Union[IterableType[str], str],
+    strs: Union[typing.Iterable[str], str],
     caseless: bool = False,
     use_regex: bool = True,
     as_keyword: bool = False,
@@ -337,7 +338,7 @@ def dict_of(key: ParserElement, value: ParserElement) -> ParserElement:
 
         text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
         attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
-        print(OneOrMore(attr_expr).parse_string(text).dump())
+        print(attr_expr[1, ...].parse_string(text).dump())
 
         attr_label = label
         attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)
@@ -461,7 +462,7 @@ def locatedExpr(expr: ParserElement) -> ParserElement:
 def nested_expr(
     opener: Union[str, ParserElement] = "(",
     closer: Union[str, ParserElement] = ")",
-    content: OptionalType[ParserElement] = None,
+    content: typing.Optional[ParserElement] = None,
     ignore_expr: ParserElement = quoted_string(),
     *,
     ignoreExpr: ParserElement = quoted_string(),
@@ -682,6 +683,8 @@ def make_xml_tags(
     return _makeTags(tag_str, True)
 
 
+any_open_tag: ParserElement
+any_close_tag: ParserElement
 any_open_tag, any_close_tag = make_html_tags(
     Word(alphas, alphanums + "_:").set_name("any tag")
 )
@@ -710,7 +713,7 @@ InfixNotationOperatorSpec = Union[
         InfixNotationOperatorArgType,
         int,
         OpAssoc,
-        OptionalType[ParseAction],
+        typing.Optional[ParseAction],
     ],
     Tuple[
         InfixNotationOperatorArgType,
@@ -840,7 +843,7 @@ def infix_notation(
         if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT):
             raise ValueError("operator must indicate right or left associativity")
 
-        thisExpr = Forward().set_name(term_name)
+        thisExpr: Forward = Forward().set_name(term_name)
         if rightLeftAssoc is OpAssoc.LEFT:
             if arity == 1:
                 matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...])
@@ -945,7 +948,7 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]
         assignment = Group(identifier + "=" + rvalue)
         stmt << (funcDef | assignment | identifier)
 
-        module_body = OneOrMore(stmt)
+        module_body = stmt[1, ...]
 
         parseTree = module_body.parseString(data)
         parseTree.pprint()
@@ -1055,7 +1058,9 @@ python_style_comment = Regex(r"#.*").set_name("Python style comment")
 
 # build list of built-in expressions, for future reference if a global default value
 # gets updated
-_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)]
+_builtin_exprs: List[ParserElement] = [
+    v for v in vars().values() if isinstance(v, ParserElement)
+]
 
 
 # pre-PEP8 compatible names
index bb444df4e5b2405f97d480a73d86927fb3260620..00c9421d3b0362526b8f90dc01e8db73841e0b61 100644 (file)
@@ -287,7 +287,7 @@ class ParseResults:
             print(numlist.parse_string("0 123 321")) # -> ['123', '321']
 
             label = Word(alphas)
-            patt = label("LABEL") + OneOrMore(Word(nums))
+            patt = label("LABEL") + Word(nums)[1, ...]
             print(patt.parse_string("AAB 123 321").dump())
 
             # Use pop() in a parse action to remove named result (note that corresponding value is not
@@ -394,7 +394,7 @@ class ParseResults:
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
 
             # use a parse action to append the reverse of the matched strings, to make a palindrome
             def make_palindrome(tokens):
@@ -487,7 +487,7 @@ class ParseResults:
 
         Example::
 
-            patt = OneOrMore(Word(alphas))
+            patt = Word(alphas)[1, ...]
             result = patt.parse_string("sldkj lsdkj sldkj")
             # even though the result prints in string-like form, it is actually a pyparsing ParseResults
             print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj']
@@ -554,7 +554,7 @@ class ParseResults:
             user_data = (Group(house_number_expr)("house_number")
                         | Group(ssn_expr)("ssn")
                         | Group(integer)("age"))
-            user_info = OneOrMore(user_data)
+            user_info = user_data[1, ...]
 
             result = user_info.parse_string("22 111-22-3333 #221B")
             for item in result:
index 991972f3fb2986d2d03951be87b07eeb6bce77bc..84a0ef17078c99e5917db41e3dbaf035fe206d7c 100644 (file)
@@ -1,7 +1,7 @@
 # testing.py
 
 from contextlib import contextmanager
-from typing import Optional
+import typing
 
 from .core import (
     ParserElement,
@@ -237,12 +237,12 @@ class pyparsing_test:
     @staticmethod
     def with_line_numbers(
         s: str,
-        start_line: Optional[int] = None,
-        end_line: Optional[int] = None,
+        start_line: typing.Optional[int] = None,
+        end_line: typing.Optional[int] = None,
         expand_tabs: bool = True,
         eol_mark: str = "|",
-        mark_spaces: Optional[str] = None,
-        mark_control: Optional[str] = None,
+        mark_spaces: typing.Optional[str] = None,
+        mark_control: typing.Optional[str] = None,
     ) -> str:
         """
         Helpful method for debugging a parser - prints a string with line and column numbers.
index 92261487c7af50ede7204c4b65299f2ed333bed1..06526203911de55da3c2a8c5ae73f48024c3f018 100644 (file)
@@ -120,7 +120,18 @@ class pyparsing_unicode(unicode_set):
     A namespace class for defining common language unicode_sets.
     """
 
-    _ranges: UnicodeRangeList = [(32, sys.maxunicode)]
+    # fmt: off
+
+    # define ranges in language character sets
+    _ranges: UnicodeRangeList = [
+        (0x0020, sys.maxunicode),
+    ]
+
+    class BasicMultilingualPlane(unicode_set):
+        "Unicode set for the Basic Multilingual Plane"
+        _ranges: UnicodeRangeList = [
+            (0x0020, 0xFFFF),
+        ]
 
     class Latin1(unicode_set):
         "Unicode set for Latin-1 Unicode Character Range"
@@ -278,11 +289,13 @@ class pyparsing_unicode(unicode_set):
 
     class CJK(Chinese, Japanese, Hangul):
         "Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range"
-        pass
 
     class Thai(unicode_set):
         "Unicode set for Thai Unicode Character Range"
-        _ranges: UnicodeRangeList = [(0x0E01, 0x0E3A), (0x0E3F, 0x0E5B)]
+        _ranges: UnicodeRangeList = [
+            (0x0E01, 0x0E3A),
+            (0x0E3F, 0x0E5B)
+        ]
 
     class Arabic(unicode_set):
         "Unicode set for Arabic Unicode Character Range"
@@ -308,7 +321,12 @@ class pyparsing_unicode(unicode_set):
 
     class Devanagari(unicode_set):
         "Unicode set for Devanagari Unicode Character Range"
-        _ranges: UnicodeRangeList = [(0x0900, 0x097F), (0xA8E0, 0xA8FF)]
+        _ranges: UnicodeRangeList = [
+            (0x0900, 0x097F),
+            (0xA8E0, 0xA8FF)
+        ]
+
+    # fmt: on
 
 
 pyparsing_unicode.Japanese._ranges = (
@@ -317,7 +335,9 @@ pyparsing_unicode.Japanese._ranges = (
     + pyparsing_unicode.Japanese.Katakana._ranges
 )
 
-# define ranges in language character sets
+pyparsing_unicode.BMP = pyparsing_unicode.BasicMultilingualPlane
+
+# add language identifiers using language Unicode
 pyparsing_unicode.العربية = pyparsing_unicode.Arabic
 pyparsing_unicode.中文 = pyparsing_unicode.Chinese
 pyparsing_unicode.кириллица = pyparsing_unicode.Cyrillic
index 84c4006cd68d0d9110c668872f6470b1feef3cc9..e9d5bed82a43192c4739559a9b25bcba1b2c29d4 100644 (file)
@@ -1,5 +1,5 @@
 packaging==21.3
-pyparsing==3.0.8
+pyparsing==3.0.9
 ordered-set==3.1.1
 more_itertools==8.8.0
 jaraco.text==3.7.0
index 0e9e3c9cd003f0b72cd1355ba06ccc31795b55a2..9ff0c87fa82c8876577f4a2f0cf0ba93fcf3d71b 100644 (file)
@@ -41,10 +41,14 @@ def validate(config: dict, filepath: _Path) -> bool:
     try:
         return validator.validate(config)
     except validator.ValidationError as ex:
-        _logger.error(f"configuration error: {ex.summary}")  # type: ignore
-        _logger.debug(ex.details)  # type: ignore
-        error = ValueError(f"invalid pyproject.toml config: {ex.name}")  # type: ignore
-        raise error from None
+        summary = f"configuration error: {ex.summary}"
+        if ex.name.strip("`") != "project":
+            # Probably it is just a field missing/misnamed, not worthy the verbosity...
+            _logger.debug(summary)
+            _logger.debug(ex.details)
+
+        error = f"invalid pyproject.toml config: {ex.name}."
+        raise ValueError(f"{error}\n{summary}") from None
 
 
 def apply_configuration(
index af128968a5a6d073ddd59f0a30c9b85fa291fa87..c2a974de6368c9f4f9b9943c94a457227370f143 100644 (file)
@@ -5,8 +5,9 @@ Load setuptools configuration from ``setup.cfg`` files.
 """
 import os
 
-import warnings
+import contextlib
 import functools
+import warnings
 from collections import defaultdict
 from functools import partial
 from functools import wraps
@@ -14,6 +15,7 @@ from typing import (TYPE_CHECKING, Callable, Any, Dict, Generic, Iterable, List,
                     Optional, Tuple, TypeVar, Union)
 
 from distutils.errors import DistutilsOptionError, DistutilsFileError
+from setuptools.extern.packaging.requirements import Requirement, InvalidRequirement
 from setuptools.extern.packaging.version import Version, InvalidVersion
 from setuptools.extern.packaging.specifiers import SpecifierSet
 from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
@@ -174,6 +176,39 @@ def parse_configuration(
     return meta, options
 
 
+def _warn_accidental_env_marker_misconfig(label: str, orig_value: str, parsed: list):
+    """Because users sometimes misinterpret this configuration:
+
+    [options.extras_require]
+    foo = bar;python_version<"4"
+
+    It looks like one requirement with an environment marker
+    but because there is no newline, it's parsed as two requirements
+    with a semicolon as separator.
+
+    Therefore, if:
+        * input string does not contain a newline AND
+        * parsed result contains two requirements AND
+        * parsing of the two parts from the result ("<first>;<second>")
+        leads in a valid Requirement with a valid marker
+    a UserWarning is shown to inform the user about the possible problem.
+    """
+    if "\n" in orig_value or len(parsed) != 2:
+        return
+
+    with contextlib.suppress(InvalidRequirement):
+        original_requirements_str = ";".join(parsed)
+        req = Requirement(original_requirements_str)
+        if req.marker is not None:
+            msg = (
+                f"One of the parsed requirements in `{label}` "
+                f"looks like a valid environment marker: '{parsed[1]}'\n"
+                "Make sure that the config is correct and check "
+                "https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#opt-2"  # noqa: E501
+            )
+            warnings.warn(msg, UserWarning)
+
+
 class ConfigHandler(Generic[Target]):
     """Handles metadata supplied in configuration files."""
 
@@ -397,33 +432,43 @@ class ConfigHandler(Generic[Target]):
         return parse
 
     @classmethod
-    def _parse_section_to_dict(cls, section_options, values_parser=None):
+    def _parse_section_to_dict_with_key(cls, section_options, values_parser):
         """Parses section options into a dictionary.
 
-        Optionally applies a given parser to values.
+        Applies a given parser to each option in a section.
 
         :param dict section_options:
-        :param callable values_parser:
+        :param callable values_parser: function with 2 args corresponding to key, value
         :rtype: dict
         """
         value = {}
-        values_parser = values_parser or (lambda val: val)
         for key, (_, val) in section_options.items():
-            value[key] = values_parser(val)
+            value[key] = values_parser(key, val)
         return value
 
+    @classmethod
+    def _parse_section_to_dict(cls, section_options, values_parser=None):
+        """Parses section options into a dictionary.
+
+        Optionally applies a given parser to each value.
+
+        :param dict section_options:
+        :param callable values_parser: function with 1 arg corresponding to option value
+        :rtype: dict
+        """
+        parser = (lambda _, v: values_parser(v)) if values_parser else (lambda _, v: v)
+        return cls._parse_section_to_dict_with_key(section_options, parser)
+
     def parse_section(self, section_options):
         """Parses configuration file section.
 
         :param dict section_options:
         """
         for (name, (_, value)) in section_options.items():
-            try:
+            with contextlib.suppress(KeyError):
+                # Keep silent for a new option may appear anytime.
                 self[name] = value
 
-            except KeyError:
-                pass  # Keep silent for a new option may appear anytime.
-
     def parse(self):
         """Parses configuration file items from one
         or more related sections.
@@ -579,9 +624,10 @@ class ConfigOptionsHandler(ConfigHandler["Distribution"]):
     def _parse_file_in_root(self, value):
         return self._parse_file(value, root_dir=self.root_dir)
 
-    def _parse_requirements_list(self, value):
+    def _parse_requirements_list(self, label: str, value: str):
         # Parse a requirements list, either by reading in a `file:`, or a list.
         parsed = self._parse_list_semicolon(self._parse_file_in_root(value))
+        _warn_accidental_env_marker_misconfig(label, value, parsed)
         # Filter it to only include lines that are not comments. `parse_list`
         # will have stripped each line and filtered out empties.
         return [line for line in parsed if not line.startswith("#")]
@@ -607,7 +653,9 @@ class ConfigOptionsHandler(ConfigHandler["Distribution"]):
                 "consider using implicit namespaces instead (PEP 420).",
                 SetuptoolsDeprecationWarning,
             ),
-            'install_requires': self._parse_requirements_list,
+            'install_requires': partial(
+                self._parse_requirements_list, "install_requires"
+            ),
             'setup_requires': self._parse_list_semicolon,
             'tests_require': self._parse_list_semicolon,
             'packages': self._parse_packages,
@@ -698,10 +746,11 @@ class ConfigOptionsHandler(ConfigHandler["Distribution"]):
 
         :param dict section_options:
         """
-        parsed = self._parse_section_to_dict(
+        parsed = self._parse_section_to_dict_with_key(
             section_options,
-            self._parse_requirements_list,
+            lambda k, v: self._parse_requirements_list(f"extras_require[{k}]", v)
         )
+
         self['extras_require'] = parsed
 
     def parse_section_data_files(self, section_options):
index 64baf1147bb78628d67ddac68b7de2c6fcd15b38..f2bbd59df81d588c93c140212ebaa1f9b99bed03 100644 (file)
@@ -73,7 +73,9 @@ class Extension(_Extension):
 
     :keyword list[str] runtime_library_dirs:
       list of directories to search for C/C++ libraries at run time
-      (for shared extensions, this is when the extension is loaded)
+      (for shared extensions, this is when the extension is loaded).
+      Setting this will cause an exception during build on Windows
+      platforms.
 
     :keyword list[str] extra_objects:
       list of extra files to link with (eg. object files not implied
@@ -113,6 +115,9 @@ class Extension(_Extension):
     :keyword bool optional:
       specifies that a build failure in the extension should not abort the
       build process, but simply not install the failing extension.
+
+    :raises setuptools.errors.PlatformError: if 'runtime_library_dirs' is
+      specified on Windows. (since v63)
     """
 
     def __init__(self, name, sources, *args, **kw):
index 200312b54d9eee38c05467d46337c0ac87d204f1..811328f52becdd109de7ff75e9a0fe44a1d2bff1 100644 (file)
@@ -1,4 +1,3 @@
-import logging
 import re
 from configparser import ConfigParser
 from inspect import cleandoc
@@ -307,7 +306,7 @@ def test_ignore_unrelated_config(tmp_path, example):
 
 
 @pytest.mark.parametrize(
-    "example, error_msg, value_shown_in_debug",
+    "example, error_msg",
     [
         (
             """
@@ -316,30 +315,18 @@ def test_ignore_unrelated_config(tmp_path, example):
             version = "1.2"
             requires = ['pywin32; platform_system=="Windows"' ]
             """,
-            "configuration error: `project` must not contain {'requires'} properties",
-            '"requires": ["pywin32; platform_system==\\"Windows\\""]',
+            "configuration error: .project. must not contain ..requires.. properties",
         ),
     ],
 )
-def test_invalid_example(tmp_path, caplog, example, error_msg, value_shown_in_debug):
-    caplog.set_level(logging.DEBUG)
+def test_invalid_example(tmp_path, example, error_msg):
     pyproject = tmp_path / "pyproject.toml"
     pyproject.write_text(cleandoc(example))
 
-    caplog.clear()
-    with pytest.raises(ValueError, match="invalid pyproject.toml"):
+    pattern = re.compile(f"invalid pyproject.toml.*{error_msg}.*", re.M | re.S)
+    with pytest.raises(ValueError, match=pattern):
         read_configuration(pyproject)
 
-    # Make sure the logs give guidance to the user
-    error_log = caplog.record_tuples[0]
-    assert error_log[1] == logging.ERROR
-    assert error_msg in error_log[2]
-
-    debug_log = caplog.record_tuples[1]
-    assert debug_log[1] == logging.DEBUG
-    debug_msg = "".join(line.strip() for line in debug_log[2].splitlines())
-    assert value_shown_in_debug in debug_msg
-
 
 @pytest.mark.parametrize("config", ("", "[tool.something]\nvalue = 42"))
 def test_empty(tmp_path, config):
index b2563a103d8b6769cd77af6ab45215af72f76a36..d2964fdaf471dc76743668963a9cf80f7d04b6bb 100644 (file)
@@ -716,6 +716,51 @@ class TestOptions:
             }
             assert dist.metadata.provides_extras == set(['pdf', 'rest'])
 
+    @pytest.mark.parametrize(
+        "config",
+        [
+            "[options.extras_require]\nfoo = bar;python_version<'3'",
+            "[options.extras_require]\nfoo = bar;os_name=='linux'",
+            "[options.extras_require]\nfoo = bar;python_version<'3'\n",
+            "[options.extras_require]\nfoo = bar;os_name=='linux'\n",
+            "[options]\ninstall_requires = bar;python_version<'3'",
+            "[options]\ninstall_requires = bar;os_name=='linux'",
+            "[options]\ninstall_requires = bar;python_version<'3'\n",
+            "[options]\ninstall_requires = bar;os_name=='linux'\n",
+        ],
+    )
+    def test_warn_accidental_env_marker_misconfig(self, config, tmpdir):
+        fake_env(tmpdir, config)
+        match = (
+            r"One of the parsed requirements in `(install_requires|extras_require.+)` "
+            "looks like a valid environment marker.*"
+        )
+        with pytest.warns(UserWarning, match=match):
+            with get_dist(tmpdir) as _:
+                pass
+
+    @pytest.mark.parametrize(
+        "config",
+        [
+            "[options.extras_require]\nfoo =\n    bar;python_version<'3'",
+            "[options.extras_require]\nfoo = bar;baz\nboo = xxx;yyy",
+            "[options.extras_require]\nfoo =\n    bar;python_version<'3'\n",
+            "[options.extras_require]\nfoo = bar;baz\nboo = xxx;yyy\n",
+            "[options.extras_require]\nfoo =\n    bar\n    python_version<'3'\n",
+            "[options]\ninstall_requires =\n    bar;python_version<'3'",
+            "[options]\ninstall_requires = bar;baz\nboo = xxx;yyy",
+            "[options]\ninstall_requires =\n    bar;python_version<'3'\n",
+            "[options]\ninstall_requires = bar;baz\nboo = xxx;yyy\n",
+            "[options]\ninstall_requires =\n    bar\n    python_version<'3'\n",
+        ],
+    )
+    def test_nowarn_accidental_env_marker_misconfig(self, config, tmpdir, recwarn):
+        fake_env(tmpdir, config)
+        with get_dist(tmpdir) as _:
+            pass
+        # The examples are valid, no warnings shown
+        assert not any(w.category == UserWarning for w in recwarn)
+
     def test_dash_preserved_extras_require(self, tmpdir):
         fake_env(tmpdir, '[options.extras_require]\n' 'foo-a = foo\n' 'foo_b = test\n')