Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.0.23: pytest is failing in few units #67

Open
kloczek opened this issue Aug 7, 2022 · 2 comments
Open

0.0.23: pytest is failing in few units #67

kloczek opened this issue Aug 7, 2022 · 2 comments
Assignees
Labels
bug Something isn't working stale

Comments

@kloczek
Copy link

kloczek commented Aug 7, 2022

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix>
  • run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>

Here is list of modules installed in build env

Package                       Version
----------------------------- -----------------
alabaster                     0.7.12
apeye                         1.2.0
appdirs                       1.4.4
attrs                         22.1.0
autodocsumm                   0.2.9
Babel                         2.10.2
beautifulsoup4                4.10.0
build                         0.8.0
CacheControl                  0.12.11
charset-normalizer            2.1.0
click                         8.1.2
codespell                     2.1.0
coincidence                   0.6.2
consolekit                    1.4.1
cssutils                      2.5.1
default-values                0.5.1
deprecation                   2.1.0
deprecation-alias             0.3.1
dict2css                      0.3.0
dist-meta                     0.5.0
distro                        1.7.0
docutils                      0.18.1
dom_toml                      0.6.0
domdf-python-tools            3.2.2.post1
editables                     0.3
extras                        1.0.0
fixtures                      4.0.0
gpg                           1.17.1-unknown
handy-archives                0.1.2
html-section                  0.2.0.post1
html5lib                      1.1
idna                          3.3
imagesize                     1.4.1
importlib-metadata            4.12.0
iniconfig                     1.1.1
Jinja2                        3.1.1
libcomps                      0.1.18
lockfile                      0.12.2
MarkupSafe                    2.1.1
mistletoe                     0.8.2
msgpack                       1.0.4
natsort                       8.0.2
packaging                     21.3
pbr                           5.9.0
pep517                        0.12.0
pip                           22.2.1
platformdirs                  2.5.2
pluggy                        1.0.0
py                            1.11.0
Pygments                      2.12.0
PyGObject                     3.42.2
pyparsing                     3.0.9
pypi-json                     0.2.1
pyproject-examples            2022.5.18
pyproject-parser              0.5.0
pytest                        7.1.2
pytest-datadir                1.3.1
pytest-regressions            2.3.1
pytest-timeout                2.1.0
python-dateutil               2.8.2
pytz                          2022.1
PyYAML                        6.0
requests                      2.28.1
rpm                           4.17.0
ruamel.yaml                   0.17.21
ruamel.yaml.clib              0.2.6
seed-intersphinx-mapping      1.0.1
setuptools                    63.4.2
shippinglabel                 1.0.1
six                           1.16.0
snowballstemmer               2.2.0
soupsieve                     2.3.2.post1
Sphinx                        5.1.1
sphinx-autodoc-typehints      1.19.1
sphinx-copybutton             0.5.0
sphinx-debuginfo              0.2.2
sphinx-jinja2-compat          0.1.2
sphinx-prompt                 1.4.0
sphinx-pyproject              0.1.0
sphinx-tabs                   3.4.1
sphinx-toolbox                3.1.2
sphinxcontrib-applehelp       1.0.2.dev20220730
sphinxcontrib-devhelp         1.0.2.dev20220730
sphinxcontrib-htmlhelp        2.0.0
sphinxcontrib-jsmath          1.0.1.dev20220730
sphinxcontrib-qthelp          1.0.3.dev20220730
sphinxcontrib-serializinghtml 1.1.5
sphinxemoji                   0.2.0
tabulate                      0.8.9
testtools                     2.5.0
toctree-plus                  0.6.0
toml                          0.10.2
tomli                         2.0.1
trove-classifiers             2022.7.30
typing_extensions             4.2.0
urllib3                       1.26.9
webencodings                  0.5.1
wheel                         0.37.1
zipp                          3.8.1
@kloczek kloczek added the bug Something isn't working label Aug 7, 2022
@kloczek
Copy link
Author

kloczek commented Aug 7, 2022

Here is pytest output:

+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-whey-0.0.23-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-whey-0.0.23-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra --ignore tests/test_cli.py --ignore tests/test_utils.py
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.13, pytest-7.1.2, pluggy-1.0.0
Test session started at 16:24:03
rootdir: /home/tkloczko/rpmbuild/BUILD/whey-0.0.23, configfile: tox.ini
plugins: datadir-1.3.1, regressions-2.3.1, timeout-2.1.0
timeout: 300.0s
timeout method: signal
timeout func_only: False
collected 240 items

tests/test_build.py ...................sss............................                                                                                               [ 20%]
tests/test_builder_methods.py s.                                                                                                                                     [ 21%]
tests/test_config.py ............................................................................FFF.....F..ss....FFF.....F..ss..................................... [ 81%]
.                                                                                                                                                                    [ 81%]
tests/test_foreman.py ...................                                                                                                                            [ 89%]
tests/test_pep517_backend.py ..................ss.....                                                                                                               [100%]

================================================================================= FAILURES =================================================================================
____________________________________________________________________ test_parse_config_errors[bad_name] ____________________________________________________________________

config = '[project]\nname = "???????12345=============☃"\nversion = "2020.0.0"', expects = <class 'dom_toml.parser.BadConfigError'>
match = "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\."
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_bad_n0')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")

tests/test_config.py:659:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

filename = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_bad_n0/pyproject.toml')

    def load_toml(filename: PathLike) -> Dict[str, Any]:  # TODO: TypedDict
        """
        Load the ``whey`` configuration mapping from the given TOML file.

        :param filename:
        """

        filename = PathPlus(filename)

        project_dir = filename.parent
        config = dom_toml.load(filename, decoder=dom_toml.decoder.TomlPureDecoder)

        parsed_config = {}
        tool_table = config.get("tool", {})

        with in_directory(project_dir):

                parsed_config.update(WheyParser().parse(tool_table.get("whey", {}), set_defaults=True))

                if "project" in config:
>                       parsed_config.update(PEP621Parser().parse(config["project"], set_defaults=True))

whey/config/__init__.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe1901bfd0>, config = {'name': '???????12345=============☃', 'version': '2020.0.0'}, set_defaults = True

    def parse(  # type: ignore[override]
        self,
        config: Dict[str, TOML_TYPES],
        set_defaults: bool = False,
        ) -> ProjectDict:
        """
        Parse the TOML configuration.

        :param config:
        :param set_defaults: If :py:obj:`True`, the values in
                :attr:`dom_toml.parser.AbstractConfigParser.defaults` and
                :attr:`dom_toml.parser.AbstractConfigParser.factories`
                will be set as defaults for the returned mapping.
        """

        dynamic_fields = set(config.get("dynamic", []))

        if "name" in dynamic_fields:
                raise BadConfigError("The 'project.name' field may not be dynamic.")
        elif "name" not in config:
                raise BadConfigError("The 'project.name' field must be provided.")

        if dynamic_fields:
                # TODO: Support the remaining fields as dynamic
                # TODO: dynamic version numbers by parsing AST for __version__ in __init__.py

                supported_dynamic = {"classifiers", "requires-python", "dependencies"}
                unsupported_fields = dynamic_fields - supported_dynamic

                if unsupported_fields:
                        supported = word_join(sorted(supported_dynamic), oxford=True, use_repr=True)
                        unsupported = word_join(sorted(unsupported_fields), oxford=True, use_repr=True)
                        raise BadConfigError(
                                        f"Unsupported dynamic {_field(len(unsupported_fields))} {unsupported}.\n"
                                        f"note: whey only supports {supported} as dynamic fields."
                                        )

        if "version" not in config:
                raise BadConfigError("The 'project.version' field must be provided.")

>       return self._parse(config, set_defaults)

whey/config/pep621.py:126:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe1901bfd0>, config = {'name': '???????12345=============☃', 'version': '2020.0.0'}, set_defaults = True

    def _parse(
                self,
                config: Dict[str, TOML_TYPES],
                set_defaults: bool = False,
                ) -> ProjectDict:

        dynamic_fields = config.get("dynamic", [])
        parsed_config = {"dynamic": dynamic_fields}

        for key in self.keys:

                if key in config and key in dynamic_fields:
                        raise BadConfigError(f"{key!r} was listed in 'project.dynamic' but a value was given.")
                elif key not in config:
                        # Ignore absent values
                        pass
                elif hasattr(self, f"parse_{key.replace('-', '_')}"):
>                       parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)

whey/config/pep621.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_name(config: Dict[str, TOML_TYPES]) -> str:
        """
        Parse the :pep621:`name` key, giving the name of the project.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Name`

        This key is required, and must be defined statically.

        Tools SHOULD normalize this name, as specified by :pep:`503`,
        as soon as it is read for internal consistency.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                name = "spam"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        normalized_name = _NormalisedName(normalize(config["name"]))
        normalized_name.unnormalized = config["name"]

        # https://packaging.python.org/specifications/core-metadata/#name
        if not name_re.match(normalized_name):
>               raise BadConfigError("The value for 'project.name' is invalid.")
E     dom_toml.parser.BadConfigError: The value for 'project.name' is invalid.

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:297: BadConfigError

During handling of the above exception, another exception occurred:

config = '[project]\nname = "???????12345=============☃"\nversion = "2020.0.0"', expects = <class 'dom_toml.parser.BadConfigError'>
match = "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\."
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_bad_n0')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")
E     AssertionError: Regex pattern "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\." does not match "The value for 'project.name' is invalid.".

tests/test_config.py:659: AssertionError
__________________________________________________________________ test_parse_config_errors[bad_version] ___________________________________________________________________

config = {'name': 'spam', 'version': '???????12345=============☃'}

    @staticmethod
    def parse_version(config: Dict[str, TOML_TYPES]) -> Version:
        """
        Parse the :pep621:`version` key, giving the version of the project as supported by :pep:`440`.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Version`

        Users SHOULD prefer to specify normalized versions.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                version = "2020.0.0"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        version = str(config["version"])

        try:
>               return Version(str(version))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:324:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'Version' object has no attribute '_version'") raised in repr()] Version object at 0x7fbe190633d0>, version = '???????12345=============☃'

    def __init__(self, version: str) -> None:

        # Validate the version and parse it into pieces
        match = self._regex.search(version)
        if not match:
>           raise InvalidVersion(f"Invalid version: '{version}'")
E           packaging.version.InvalidVersion: Invalid version: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/version.py:266: InvalidVersion

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "???????12345=============☃"', expects = <class 'packaging.version.InvalidVersion'>
match = "Invalid\\ version:\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'", tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_bad_v0')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")

tests/test_config.py:659:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
whey/config/__init__.py:82: in load_toml
    parsed_config.update(PEP621Parser().parse(config["project"], set_defaults=True))
whey/config/pep621.py:126: in parse
    return self._parse(config, set_defaults)
whey/config/pep621.py:72: in _parse
    parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': 'spam', 'version': '???????12345=============☃'}

    @staticmethod
    def parse_version(config: Dict[str, TOML_TYPES]) -> Version:
        """
        Parse the :pep621:`version` key, giving the version of the project as supported by :pep:`440`.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Version`

        Users SHOULD prefer to specify normalized versions.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                version = "2020.0.0"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        version = str(config["version"])

        try:
                return Version(str(version))
        except InvalidVersion as e:
>               raise BadConfigError(str(e))
E     dom_toml.parser.BadConfigError: Invalid version: '???????12345=============☃'

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:326: BadConfigError
______________________________________________________________ test_parse_config_errors[bad_requires_python] _______________________________________________________________

self = <[AttributeError("'SpecifierSet' object has no attribute '_prereleases'") raised in repr()] SpecifierSet object at 0x7fbe18f5cd60>
specifiers = '???????12345=============☃', prereleases = None

    def __init__(
        self, specifiers: str = "", prereleases: Optional[bool] = None
    ) -> None:

        # Split on , to break each individual specifier into it's own item, and
        # strip each item to remove leading/trailing whitespace.
        split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]

        # Parsed each individual specifier, attempting first to make it a
        # Specifier and falling back to a LegacySpecifier.
        parsed: Set[_IndividualSpecifier] = set()
        for specifier in split_specifiers:
            try:
>               parsed.add(Specifier(specifier))

/usr/lib/python3.8/site-packages/packaging/specifiers.py:634:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'Specifier' object has no attribute '_prereleases'") raised in repr()] Specifier object at 0x7fbe18f5cdc0>, spec = '???????12345=============☃'
prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
        match = self._regex.search(spec)
        if not match:
>           raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
E           packaging.specifiers.InvalidSpecifier: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/specifiers.py:98: InvalidSpecifier

During handling of the above exception, another exception occurred:

config = {'name': 'spam', 'requires-python': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_requires_python(config: Dict[str, TOML_TYPES]) -> SpecifierSet:
        """
        Parse the :pep621:`requires-python` key, giving the Python version requirements of the project.

        The requirement should be in the form of a :pep:`508` marker.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Requires-Python`

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                requires-python = ">=3.6"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.

        :rtype:

        .. latex:clearpage::
        """

        version = str(config["requires-python"])

        try:
>               return SpecifierSet(str(version))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:495:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'SpecifierSet' object has no attribute '_prereleases'") raised in repr()] SpecifierSet object at 0x7fbe18f5cd60>
specifiers = '???????12345=============☃', prereleases = None

    def __init__(
        self, specifiers: str = "", prereleases: Optional[bool] = None
    ) -> None:

        # Split on , to break each individual specifier into it's own item, and
        # strip each item to remove leading/trailing whitespace.
        split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]

        # Parsed each individual specifier, attempting first to make it a
        # Specifier and falling back to a LegacySpecifier.
        parsed: Set[_IndividualSpecifier] = set()
        for specifier in split_specifiers:
            try:
                parsed.add(Specifier(specifier))
            except InvalidSpecifier:
>               parsed.add(LegacySpecifier(specifier))

/usr/lib/python3.8/site-packages/packaging/specifiers.py:636:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'LegacySpecifier' object has no attribute '_prereleases'") raised in repr()] LegacySpecifier object at 0x7fbe18f5cdf0>
spec = '???????12345=============☃', prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
>       super().__init__(spec, prereleases)

/usr/lib/python3.8/site-packages/packaging/specifiers.py:253:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'LegacySpecifier' object has no attribute '_prereleases'") raised in repr()] LegacySpecifier object at 0x7fbe18f5cdf0>
spec = '???????12345=============☃', prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
        match = self._regex.search(spec)
        if not match:
>           raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
E           packaging.specifiers.InvalidSpecifier: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/specifiers.py:98: InvalidSpecifier

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\nrequires-python = "???????12345=============☃"', expects = <class 'packaging.specifiers.InvalidSpecifier'>
match = "Invalid\\ specifier:\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'"
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_bad_r0')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")

tests/test_config.py:659:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
whey/config/__init__.py:82: in load_toml
    parsed_config.update(PEP621Parser().parse(config["project"], set_defaults=True))
whey/config/pep621.py:126: in parse
    return self._parse(config, set_defaults)
whey/config/pep621.py:72: in _parse
    parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': 'spam', 'requires-python': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_requires_python(config: Dict[str, TOML_TYPES]) -> SpecifierSet:
        """
        Parse the :pep621:`requires-python` key, giving the Python version requirements of the project.

        The requirement should be in the form of a :pep:`508` marker.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Requires-Python`

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                requires-python = ">=3.6"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.

        :rtype:

        .. latex:clearpage::
        """

        version = str(config["requires-python"])

        try:
                return SpecifierSet(str(version))
        except InvalidSpecifier as e:
>               raise BadConfigError(str(e))
E     dom_toml.parser.BadConfigError: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:497: BadConfigError
________________________________________________________ test_parse_config_errors[dependencies_invalid_requirement] ________________________________________________________

self = <[AttributeError("'ComparableRequirement' object has no attribute 'name'") raised in repr()] ComparableRequirement object at 0x7fbe18f7dd60>
requirement_string = 'foo]]]'

    def __init__(self, requirement_string: str) -> None:
        try:
>           req = REQUIREMENT.parseString(requirement_string)

/usr/lib/python3.8/site-packages/packaging/requirements.py:102:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = {string_start Combine:({W:(0-9A-Za-z) [{W:(0-9A-Za-z) | {[W:(-._)]... W:(0-9A-Za-z)}}]...}) [Suppress:('[') [Combine:(... {string enclosed in "'" | string enclosed in '"'}) | Group:({{Suppress:('(') : ...} Suppress:(') Empty}]}} string_end}
instring = 'foo]]]', parse_all = False

    def parse_string(
        self, instring: str, parse_all: bool = False, *, parseAll: bool = False
    ) -> ParseResults:
        """
        Parse a string with respect to the parser definition. This function is intended as the primary interface to the
        client code.

        :param instring: The input string to be parsed.
        :param parse_all: If set, the entire input string must match the grammar.
        :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release.
        :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar.
        :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or
          an object with attributes if the given parser includes results names.

        If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This
        is also equivalent to ending the grammar with :class:`StringEnd`().

        To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are
        converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string
        contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string
        being parsed, one can ensure a consistent view of the input string by doing one of the following:

        - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`),
        - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the
          parse action's ``s`` argument, or
        - explicitly expand the tabs in your input string before calling ``parse_string``.

        Examples:

        By default, partial matches are OK.

        >>> res = Word('a').parse_string('aaaaabaaa')
        >>> print(res)
        ['aaaaa']

        The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children
        directly to see more examples.

        It raises an exception if parse_all flag is set and instring does not match the whole grammar.

        >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True)
        Traceback (most recent call last):
        ...
        pyparsing.ParseException: Expected end of text, found 'b'  (at char 5), (line:1, col:6)
        """
        parseAll = parse_all or parseAll

        ParserElement.reset_cache()
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()
        if not self.keepTabs:
            instring = instring.expandtabs()
        try:
            loc, tokens = self._parse(instring, 0)
            if parseAll:
                loc = self.preParse(instring, loc)
                se = Empty() + StringEnd()
                se._parse(instring, loc)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clearing out pyparsing internal stack trace
>               raise exc.with_traceback(None)
E               pyparsing.exceptions.ParseException: Expected string_end, found ']'  (at char 3), (line:1, col:4)

/usr/lib/python3.8/site-packages/pyparsing/core.py:1141: ParseException

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\ndependencies = ["foo]]]"]', expects = <class 'packaging.requirements.InvalidRequirement'>
match = '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end'
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_depen1')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")

tests/test_config.py:659:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

filename = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_depen1/pyproject.toml')

    def load_toml(filename: PathLike) -> Dict[str, Any]:  # TODO: TypedDict
        """
        Load the ``whey`` configuration mapping from the given TOML file.

        :param filename:
        """

        filename = PathPlus(filename)

        project_dir = filename.parent
        config = dom_toml.load(filename, decoder=dom_toml.decoder.TomlPureDecoder)

        parsed_config = {}
        tool_table = config.get("tool", {})

        with in_directory(project_dir):

                parsed_config.update(WheyParser().parse(tool_table.get("whey", {}), set_defaults=True))

                if "project" in config:
>                       parsed_config.update(PEP621Parser().parse(config["project"], set_defaults=True))

whey/config/__init__.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18f7dbb0>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}, set_defaults = True

    def parse(  # type: ignore[override]
        self,
        config: Dict[str, TOML_TYPES],
        set_defaults: bool = False,
        ) -> ProjectDict:
        """
        Parse the TOML configuration.

        :param config:
        :param set_defaults: If :py:obj:`True`, the values in
                :attr:`dom_toml.parser.AbstractConfigParser.defaults` and
                :attr:`dom_toml.parser.AbstractConfigParser.factories`
                will be set as defaults for the returned mapping.
        """

        dynamic_fields = set(config.get("dynamic", []))

        if "name" in dynamic_fields:
                raise BadConfigError("The 'project.name' field may not be dynamic.")
        elif "name" not in config:
                raise BadConfigError("The 'project.name' field must be provided.")

        if dynamic_fields:
                # TODO: Support the remaining fields as dynamic
                # TODO: dynamic version numbers by parsing AST for __version__ in __init__.py

                supported_dynamic = {"classifiers", "requires-python", "dependencies"}
                unsupported_fields = dynamic_fields - supported_dynamic

                if unsupported_fields:
                        supported = word_join(sorted(supported_dynamic), oxford=True, use_repr=True)
                        unsupported = word_join(sorted(unsupported_fields), oxford=True, use_repr=True)
                        raise BadConfigError(
                                        f"Unsupported dynamic {_field(len(unsupported_fields))} {unsupported}.\n"
                                        f"note: whey only supports {supported} as dynamic fields."
                                        )

        if "version" not in config:
                raise BadConfigError("The 'project.version' field must be provided.")

>       return self._parse(config, set_defaults)

whey/config/pep621.py:126:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18f7dbb0>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}, set_defaults = True

    def _parse(
                self,
                config: Dict[str, TOML_TYPES],
                set_defaults: bool = False,
                ) -> ProjectDict:

        dynamic_fields = config.get("dynamic", [])
        parsed_config = {"dynamic": dynamic_fields}

        for key in self.keys:

                if key in config and key in dynamic_fields:
                        raise BadConfigError(f"{key!r} was listed in 'project.dynamic' but a value was given.")
                elif key not in config:
                        # Ignore absent values
                        pass
                elif hasattr(self, f"parse_{key.replace('-', '_')}"):
>                       parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)

whey/config/pep621.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18f7dbb0>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}

    def parse_dependencies(self, config: Dict[str, TOML_TYPES]) -> List[ComparableRequirement]:
        """
        Parse the :pep621:`dependencies` key, giving the dependencies of the project.

        * **Format**: :toml:`Array` of :pep:`508` strings
        * **Core Metadata**: :core-meta:`Requires-Dist`

        Each string MUST be formatted as a valid :pep:`508` string.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                dependencies = [
                        "httpx",
                        "gidgethub[httpx]>4.0.0",
                        "django>2.1; os_name != 'nt'",
                        "django>2.0; os_name == 'nt'"
                ]

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        parsed_dependencies = set()

        key_path = [self.table_name, "dependencies"]

        self.assert_sequence_not_str(config["dependencies"], key_path)

        for idx, keyword in enumerate(config["dependencies"]):
                self.assert_indexed_type(keyword, str, key_path, idx=idx)
>               parsed_dependencies.add(ComparableRequirement(keyword))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:899:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'ComparableRequirement' object has no attribute 'name'") raised in repr()] ComparableRequirement object at 0x7fbe18f7dd60>
requirement_string = 'foo]]]'

    def __init__(self, requirement_string: str) -> None:
        try:
            req = REQUIREMENT.parseString(requirement_string)
        except ParseException as e:
>           raise InvalidRequirement(
                f'Parse error at "{ requirement_string[e.loc : e.loc + 8]!r}": {e.msg}'
            )
E           packaging.requirements.InvalidRequirement: Parse error at "']]]'": Expected string_end

/usr/lib/python3.8/site-packages/packaging/requirements.py:104: InvalidRequirement

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\ndependencies = ["foo]]]"]', expects = <class 'packaging.requirements.InvalidRequirement'>
match = '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end'
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_parse_config_errors_depen1')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param('', KeyError, "'project' table not found in '.*'", id="no_config"),
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_parse_config_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with pytest.raises(expects, match=match):
>               load_toml(tmp_pathplus / "pyproject.toml")
E     AssertionError: Regex pattern '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end' does not match 'Parse error at "\']]]\'": Expected string_end'.

tests/test_config.py:659: AssertionError
_________________________________________________________________ test_pep621parser_class_errors[bad_name] _________________________________________________________________

config = '[project]\nname = "???????12345=============☃"\nversion = "2020.0.0"', expects = <class 'dom_toml.parser.BadConfigError'>
match = "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\."
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors3')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])

tests/test_config.py:678:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe19080eb0>, config = {'name': '???????12345=============☃', 'version': '2020.0.0'}, set_defaults = False

    def parse(  # type: ignore[override]
        self,
        config: Dict[str, TOML_TYPES],
        set_defaults: bool = False,
        ) -> ProjectDict:
        """
        Parse the TOML configuration.

        :param config:
        :param set_defaults: If :py:obj:`True`, the values in
                :attr:`dom_toml.parser.AbstractConfigParser.defaults` and
                :attr:`dom_toml.parser.AbstractConfigParser.factories`
                will be set as defaults for the returned mapping.
        """

        dynamic_fields = set(config.get("dynamic", []))

        if "name" in dynamic_fields:
                raise BadConfigError("The 'project.name' field may not be dynamic.")
        elif "name" not in config:
                raise BadConfigError("The 'project.name' field must be provided.")

        if dynamic_fields:
                # TODO: Support the remaining fields as dynamic
                # TODO: dynamic version numbers by parsing AST for __version__ in __init__.py

                supported_dynamic = {"classifiers", "requires-python", "dependencies"}
                unsupported_fields = dynamic_fields - supported_dynamic

                if unsupported_fields:
                        supported = word_join(sorted(supported_dynamic), oxford=True, use_repr=True)
                        unsupported = word_join(sorted(unsupported_fields), oxford=True, use_repr=True)
                        raise BadConfigError(
                                        f"Unsupported dynamic {_field(len(unsupported_fields))} {unsupported}.\n"
                                        f"note: whey only supports {supported} as dynamic fields."
                                        )

        if "version" not in config:
                raise BadConfigError("The 'project.version' field must be provided.")

>       return self._parse(config, set_defaults)

whey/config/pep621.py:126:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe19080eb0>, config = {'name': '???????12345=============☃', 'version': '2020.0.0'}, set_defaults = False

    def _parse(
                self,
                config: Dict[str, TOML_TYPES],
                set_defaults: bool = False,
                ) -> ProjectDict:

        dynamic_fields = config.get("dynamic", [])
        parsed_config = {"dynamic": dynamic_fields}

        for key in self.keys:

                if key in config and key in dynamic_fields:
                        raise BadConfigError(f"{key!r} was listed in 'project.dynamic' but a value was given.")
                elif key not in config:
                        # Ignore absent values
                        pass
                elif hasattr(self, f"parse_{key.replace('-', '_')}"):
>                       parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)

whey/config/pep621.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_name(config: Dict[str, TOML_TYPES]) -> str:
        """
        Parse the :pep621:`name` key, giving the name of the project.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Name`

        This key is required, and must be defined statically.

        Tools SHOULD normalize this name, as specified by :pep:`503`,
        as soon as it is read for internal consistency.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                name = "spam"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        normalized_name = _NormalisedName(normalize(config["name"]))
        normalized_name.unnormalized = config["name"]

        # https://packaging.python.org/specifications/core-metadata/#name
        if not name_re.match(normalized_name):
>               raise BadConfigError("The value for 'project.name' is invalid.")
E     dom_toml.parser.BadConfigError: The value for 'project.name' is invalid.

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:297: BadConfigError

During handling of the above exception, another exception occurred:

config = '[project]\nname = "???????12345=============☃"\nversion = "2020.0.0"', expects = <class 'dom_toml.parser.BadConfigError'>
match = "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\."
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors3')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])
E     AssertionError: Regex pattern "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'project\\.name'\\ is\\ invalid\\." does not match "The value for 'project.name' is invalid.".

tests/test_config.py:678: AssertionError
_______________________________________________________________ test_pep621parser_class_errors[bad_version] ________________________________________________________________

config = {'name': 'spam', 'version': '???????12345=============☃'}

    @staticmethod
    def parse_version(config: Dict[str, TOML_TYPES]) -> Version:
        """
        Parse the :pep621:`version` key, giving the version of the project as supported by :pep:`440`.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Version`

        Users SHOULD prefer to specify normalized versions.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                version = "2020.0.0"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        version = str(config["version"])

        try:
>               return Version(str(version))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:324:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'Version' object has no attribute '_version'") raised in repr()] Version object at 0x7fbe190a9670>, version = '???????12345=============☃'

    def __init__(self, version: str) -> None:

        # Validate the version and parse it into pieces
        match = self._regex.search(version)
        if not match:
>           raise InvalidVersion(f"Invalid version: '{version}'")
E           packaging.version.InvalidVersion: Invalid version: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/version.py:266: InvalidVersion

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "???????12345=============☃"', expects = <class 'packaging.version.InvalidVersion'>
match = "Invalid\\ version:\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'", tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors4')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])

tests/test_config.py:678:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
whey/config/pep621.py:126: in parse
    return self._parse(config, set_defaults)
whey/config/pep621.py:72: in _parse
    parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': 'spam', 'version': '???????12345=============☃'}

    @staticmethod
    def parse_version(config: Dict[str, TOML_TYPES]) -> Version:
        """
        Parse the :pep621:`version` key, giving the version of the project as supported by :pep:`440`.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Version`

        Users SHOULD prefer to specify normalized versions.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                version = "2020.0.0"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        version = str(config["version"])

        try:
                return Version(str(version))
        except InvalidVersion as e:
>               raise BadConfigError(str(e))
E     dom_toml.parser.BadConfigError: Invalid version: '???????12345=============☃'

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:326: BadConfigError
___________________________________________________________ test_pep621parser_class_errors[bad_requires_python] ____________________________________________________________

self = <[AttributeError("'SpecifierSet' object has no attribute '_prereleases'") raised in repr()] SpecifierSet object at 0x7fbe18ef53a0>
specifiers = '???????12345=============☃', prereleases = None

    def __init__(
        self, specifiers: str = "", prereleases: Optional[bool] = None
    ) -> None:

        # Split on , to break each individual specifier into it's own item, and
        # strip each item to remove leading/trailing whitespace.
        split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]

        # Parsed each individual specifier, attempting first to make it a
        # Specifier and falling back to a LegacySpecifier.
        parsed: Set[_IndividualSpecifier] = set()
        for specifier in split_specifiers:
            try:
>               parsed.add(Specifier(specifier))

/usr/lib/python3.8/site-packages/packaging/specifiers.py:634:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'Specifier' object has no attribute '_prereleases'") raised in repr()] Specifier object at 0x7fbe18ef5280>, spec = '???????12345=============☃'
prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
        match = self._regex.search(spec)
        if not match:
>           raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
E           packaging.specifiers.InvalidSpecifier: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/specifiers.py:98: InvalidSpecifier

During handling of the above exception, another exception occurred:

config = {'name': 'spam', 'requires-python': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_requires_python(config: Dict[str, TOML_TYPES]) -> SpecifierSet:
        """
        Parse the :pep621:`requires-python` key, giving the Python version requirements of the project.

        The requirement should be in the form of a :pep:`508` marker.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Requires-Python`

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                requires-python = ">=3.6"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.

        :rtype:

        .. latex:clearpage::
        """

        version = str(config["requires-python"])

        try:
>               return SpecifierSet(str(version))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:495:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'SpecifierSet' object has no attribute '_prereleases'") raised in repr()] SpecifierSet object at 0x7fbe18ef53a0>
specifiers = '???????12345=============☃', prereleases = None

    def __init__(
        self, specifiers: str = "", prereleases: Optional[bool] = None
    ) -> None:

        # Split on , to break each individual specifier into it's own item, and
        # strip each item to remove leading/trailing whitespace.
        split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]

        # Parsed each individual specifier, attempting first to make it a
        # Specifier and falling back to a LegacySpecifier.
        parsed: Set[_IndividualSpecifier] = set()
        for specifier in split_specifiers:
            try:
                parsed.add(Specifier(specifier))
            except InvalidSpecifier:
>               parsed.add(LegacySpecifier(specifier))

/usr/lib/python3.8/site-packages/packaging/specifiers.py:636:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'LegacySpecifier' object has no attribute '_prereleases'") raised in repr()] LegacySpecifier object at 0x7fbe18ef5400>
spec = '???????12345=============☃', prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
>       super().__init__(spec, prereleases)

/usr/lib/python3.8/site-packages/packaging/specifiers.py:253:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'LegacySpecifier' object has no attribute '_prereleases'") raised in repr()] LegacySpecifier object at 0x7fbe18ef5400>
spec = '???????12345=============☃', prereleases = None

    def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
        match = self._regex.search(spec)
        if not match:
>           raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
E           packaging.specifiers.InvalidSpecifier: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/packaging/specifiers.py:98: InvalidSpecifier

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\nrequires-python = "???????12345=============☃"', expects = <class 'packaging.specifiers.InvalidSpecifier'>
match = "Invalid\\ specifier:\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'"
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors5')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])

tests/test_config.py:678:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
whey/config/pep621.py:126: in parse
    return self._parse(config, set_defaults)
whey/config/pep621.py:72: in _parse
    parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

config = {'name': 'spam', 'requires-python': '???????12345=============☃', 'version': '2020.0.0'}

    @staticmethod
    def parse_requires_python(config: Dict[str, TOML_TYPES]) -> SpecifierSet:
        """
        Parse the :pep621:`requires-python` key, giving the Python version requirements of the project.

        The requirement should be in the form of a :pep:`508` marker.

        * **Format**: :toml:`String`
        * **Core Metadata**: :core-meta:`Requires-Python`

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                requires-python = ">=3.6"

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.

        :rtype:

        .. latex:clearpage::
        """

        version = str(config["requires-python"])

        try:
                return SpecifierSet(str(version))
        except InvalidSpecifier as e:
>               raise BadConfigError(str(e))
E     dom_toml.parser.BadConfigError: Invalid specifier: '???????12345=============☃'

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:497: BadConfigError
_____________________________________________________ test_pep621parser_class_errors[dependencies_invalid_requirement] _____________________________________________________

self = <[AttributeError("'ComparableRequirement' object has no attribute 'name'") raised in repr()] ComparableRequirement object at 0x7fbe1a0f9160>
requirement_string = 'foo]]]'

    def __init__(self, requirement_string: str) -> None:
        try:
>           req = REQUIREMENT.parseString(requirement_string)

/usr/lib/python3.8/site-packages/packaging/requirements.py:102:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = {string_start Combine:({W:(0-9A-Za-z) [{W:(0-9A-Za-z) | {[W:(-._)]... W:(0-9A-Za-z)}}]...}) [Suppress:('[') [Combine:(... {string enclosed in "'" | string enclosed in '"'}) | Group:({{Suppress:('(') : ...} Suppress:(') Empty}]}} string_end}
instring = 'foo]]]', parse_all = False

    def parse_string(
        self, instring: str, parse_all: bool = False, *, parseAll: bool = False
    ) -> ParseResults:
        """
        Parse a string with respect to the parser definition. This function is intended as the primary interface to the
        client code.

        :param instring: The input string to be parsed.
        :param parse_all: If set, the entire input string must match the grammar.
        :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release.
        :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar.
        :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or
          an object with attributes if the given parser includes results names.

        If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This
        is also equivalent to ending the grammar with :class:`StringEnd`().

        To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are
        converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string
        contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string
        being parsed, one can ensure a consistent view of the input string by doing one of the following:

        - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`),
        - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the
          parse action's ``s`` argument, or
        - explicitly expand the tabs in your input string before calling ``parse_string``.

        Examples:

        By default, partial matches are OK.

        >>> res = Word('a').parse_string('aaaaabaaa')
        >>> print(res)
        ['aaaaa']

        The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children
        directly to see more examples.

        It raises an exception if parse_all flag is set and instring does not match the whole grammar.

        >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True)
        Traceback (most recent call last):
        ...
        pyparsing.ParseException: Expected end of text, found 'b'  (at char 5), (line:1, col:6)
        """
        parseAll = parse_all or parseAll

        ParserElement.reset_cache()
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()
        if not self.keepTabs:
            instring = instring.expandtabs()
        try:
            loc, tokens = self._parse(instring, 0)
            if parseAll:
                loc = self.preParse(instring, loc)
                se = Empty() + StringEnd()
                se._parse(instring, loc)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clearing out pyparsing internal stack trace
>               raise exc.with_traceback(None)
E               pyparsing.exceptions.ParseException: Expected string_end, found ']'  (at char 3), (line:1, col:4)

/usr/lib/python3.8/site-packages/pyparsing/core.py:1141: ParseException

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\ndependencies = ["foo]]]"]', expects = <class 'packaging.requirements.InvalidRequirement'>
match = '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end'
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors11')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])

tests/test_config.py:678:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18e0d820>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}, set_defaults = False

    def parse(  # type: ignore[override]
        self,
        config: Dict[str, TOML_TYPES],
        set_defaults: bool = False,
        ) -> ProjectDict:
        """
        Parse the TOML configuration.

        :param config:
        :param set_defaults: If :py:obj:`True`, the values in
                :attr:`dom_toml.parser.AbstractConfigParser.defaults` and
                :attr:`dom_toml.parser.AbstractConfigParser.factories`
                will be set as defaults for the returned mapping.
        """

        dynamic_fields = set(config.get("dynamic", []))

        if "name" in dynamic_fields:
                raise BadConfigError("The 'project.name' field may not be dynamic.")
        elif "name" not in config:
                raise BadConfigError("The 'project.name' field must be provided.")

        if dynamic_fields:
                # TODO: Support the remaining fields as dynamic
                # TODO: dynamic version numbers by parsing AST for __version__ in __init__.py

                supported_dynamic = {"classifiers", "requires-python", "dependencies"}
                unsupported_fields = dynamic_fields - supported_dynamic

                if unsupported_fields:
                        supported = word_join(sorted(supported_dynamic), oxford=True, use_repr=True)
                        unsupported = word_join(sorted(unsupported_fields), oxford=True, use_repr=True)
                        raise BadConfigError(
                                        f"Unsupported dynamic {_field(len(unsupported_fields))} {unsupported}.\n"
                                        f"note: whey only supports {supported} as dynamic fields."
                                        )

        if "version" not in config:
                raise BadConfigError("The 'project.version' field must be provided.")

>       return self._parse(config, set_defaults)

whey/config/pep621.py:126:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18e0d820>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}, set_defaults = False

    def _parse(
                self,
                config: Dict[str, TOML_TYPES],
                set_defaults: bool = False,
                ) -> ProjectDict:

        dynamic_fields = config.get("dynamic", [])
        parsed_config = {"dynamic": dynamic_fields}

        for key in self.keys:

                if key in config and key in dynamic_fields:
                        raise BadConfigError(f"{key!r} was listed in 'project.dynamic' but a value was given.")
                elif key not in config:
                        # Ignore absent values
                        pass
                elif hasattr(self, f"parse_{key.replace('-', '_')}"):
>                       parsed_config[key] = getattr(self, f"parse_{key.replace('-', '_')}")(config)

whey/config/pep621.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <whey.config.pep621.PEP621Parser object at 0x7fbe18e0d820>, config = {'dependencies': ['foo]]]'], 'name': 'spam', 'version': '2020.0.0'}

    def parse_dependencies(self, config: Dict[str, TOML_TYPES]) -> List[ComparableRequirement]:
        """
        Parse the :pep621:`dependencies` key, giving the dependencies of the project.

        * **Format**: :toml:`Array` of :pep:`508` strings
        * **Core Metadata**: :core-meta:`Requires-Dist`

        Each string MUST be formatted as a valid :pep:`508` string.

        :bold-title:`Example:`

        .. code-block:: TOML

                [project]
                dependencies = [
                        "httpx",
                        "gidgethub[httpx]>4.0.0",
                        "django>2.1; os_name != 'nt'",
                        "django>2.0; os_name == 'nt'"
                ]

        :param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
        """

        parsed_dependencies = set()

        key_path = [self.table_name, "dependencies"]

        self.assert_sequence_not_str(config["dependencies"], key_path)

        for idx, keyword in enumerate(config["dependencies"]):
                self.assert_indexed_type(keyword, str, key_path, idx=idx)
>               parsed_dependencies.add(ComparableRequirement(keyword))

/usr/lib/python3.8/site-packages/pyproject_parser/parsers.py:899:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'ComparableRequirement' object has no attribute 'name'") raised in repr()] ComparableRequirement object at 0x7fbe1a0f9160>
requirement_string = 'foo]]]'

    def __init__(self, requirement_string: str) -> None:
        try:
            req = REQUIREMENT.parseString(requirement_string)
        except ParseException as e:
>           raise InvalidRequirement(
                f'Parse error at "{ requirement_string[e.loc : e.loc + 8]!r}": {e.msg}'
            )
E           packaging.requirements.InvalidRequirement: Parse error at "']]]'": Expected string_end

/usr/lib/python3.8/site-packages/packaging/requirements.py:104: InvalidRequirement

During handling of the above exception, another exception occurred:

config = '[project]\nname = "spam"\nversion = "2020.0.0"\ndependencies = ["foo]]]"]', expects = <class 'packaging.requirements.InvalidRequirement'>
match = '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end'
tmp_pathplus = PosixPathPlus('/tmp/pytest-of-tkloczko/pytest-47/test_pep621parser_class_errors11')

    @pytest.mark.parametrize(
                "config, expects, match",
                [
                                pytest.param(
                                                '[project]\nname = "spam"',
                                                BadConfigError,
                                                "The 'project.version' field must be provided.",
                                                id="no_version"
                                                ),
                                *bad_pep621_config,
                                ]
                )
    def test_pep621parser_class_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus):
        (tmp_pathplus / "pyproject.toml").write_clean(config)

        with in_directory(tmp_pathplus), pytest.raises(expects, match=match):
>               PEP621Parser().parse(dom_toml.load(tmp_pathplus / "pyproject.toml")["project"])
E     AssertionError: Regex pattern '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": Expected string_end' does not match 'Parse error at "\']]]\'": Expected string_end'.

tests/test_config.py:678: AssertionError
=========================================================================== slowest 25 durations ===========================================================================
0.04s call     tests/test_build.py::test_build_additional_files
0.04s call     tests/test_build.py::test_build_additional_files_source_dir
0.04s call     tests/test_pep517_backend.py::test_build_additional_files[1]
0.04s call     tests/test_pep517_backend.py::test_build_additional_files[None]
0.04s call     tests/test_build.py::test_build_success[optional-dependencies]
0.04s call     tests/test_foreman.py::test_build_success[optional-dependencies]
0.04s call     tests/test_pep517_backend.py::test_build_additional_files[0]
0.04s call     tests/test_foreman.py::test_build_additional_files
0.03s call     tests/test_build.py::test_build_complete[LONG_REQUIREMENTS]
0.03s call     tests/test_build.py::test_build_complete[COMPLETE_A]
0.03s call     tests/test_build.py::test_build_wheel_from_sdist[DYNAMIC_REQUIREMENTS]
0.03s call     tests/test_build.py::test_build_wheel_from_sdist[LONG_REQUIREMENTS]
0.03s call     tests/test_build.py::test_build_source_dir_complete[COMPLETE_A]
0.03s call     tests/test_pep517_backend.py::test_build_complete[COMPLETE_B-1]
0.03s call     tests/test_build.py::test_build_wheel_from_sdist[COMPLETE_B]
0.03s call     tests/test_build.py::test_build_source_dir_complete[COMPLETE_B]
0.03s call     tests/test_build.py::test_build_source_dir_different_package
0.03s call     tests/test_build.py::test_build_wheel_from_sdist[COMPLETE_A]
0.03s call     tests/test_build.py::test_build_complete[COMPLETE_B]
0.03s call     tests/test_build.py::test_build_wheel_from_sdist_source_dir[COMPLETE_A]
0.03s call     tests/test_build.py::test_build_markdown_readme
0.03s call     tests/test_build.py::test_build_wheel_from_sdist_source_dir[COMPLETE_B]
0.03s call     tests/test_pep517_backend.py::test_build_complete[COMPLETE_A-None]
0.03s call     tests/test_pep517_backend.py::test_build_complete[COMPLETE_A-1]
0.03s call     tests/test_pep517_backend.py::test_build_complete[COMPLETE_B-0]
========================================================================= short test summary info ==========================================================================
SKIPPED [3] tests/test_build.py:251: Not needed on Python v3.6.0.
SKIPPED [1] tests/test_builder_methods.py:21: Not needed on Python v3.6.0.
SKIPPED [2] tests/test_config.py:642: Message differs on Windows.
SKIPPED [2] tests/test_config.py:662: Message differs on Windows.
SKIPPED [2] tests/test_pep517_backend.py:278: Not needed on Python v3.6.0.
FAILED tests/test_config.py::test_parse_config_errors[bad_name] - AssertionError: Regex pattern "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ 'projec...
FAILED tests/test_config.py::test_parse_config_errors[bad_version] - dom_toml.parser.BadConfigError: Invalid version: '???????12345=============☃'
FAILED tests/test_config.py::test_parse_config_errors[bad_requires_python] - dom_toml.parser.BadConfigError: Invalid specifier: '???????12345=============☃'
FAILED tests/test_config.py::test_parse_config_errors[dependencies_invalid_requirement] - AssertionError: Regex pattern '\'foo]]]\'\\n    Parse error at \\"\']]]\'\\": E...
FAILED tests/test_config.py::test_pep621parser_class_errors[bad_name] - AssertionError: Regex pattern "The\\ value\\ '\\?\\?\\?\\?\\?\\?\\?12345=============☃'\\ for\\ '...
FAILED tests/test_config.py::test_pep621parser_class_errors[bad_version] - dom_toml.parser.BadConfigError: Invalid version: '???????12345=============☃'
FAILED tests/test_config.py::test_pep621parser_class_errors[bad_requires_python] - dom_toml.parser.BadConfigError: Invalid specifier: '???????12345=============☃'
FAILED tests/test_config.py::test_pep621parser_class_errors[dependencies_invalid_requirement] - AssertionError: Regex pattern '\'foo]]]\'\\n    Parse error at \\"\']]]\'...
================================================================ 8 failed, 222 passed, 10 skipped in 4.54s =================================================================

@kloczek
Copy link
Author

kloczek commented Aug 7, 2022

I'm going to add above failing units temporary to --deselect list so .. no rush 😋

BTW: I have question. In pytest parames I've dded to --ignore list two fiels whoch are doing conda related test
As I have no packaged conda and don;t see for now sense to package it I'm ignoring those test.
Are those two files contains only conda relatest tests? If not .. is it would be possibe to separate those conda tests into files with onl;y conda tests and or make conda tests optional? 🤔

@stale stale bot added the stale label Feb 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working stale
Projects
None yet
Development

No branches or pull requests

2 participants