repo-helper / whey

A simple Python wheel builder for simple projects.
https://whey.readthedocs.io/en/latest
MIT License
33 stars 3 forks source link

0.0.23: pytest is failing in few units #67

Open kloczek opened 2 years ago

kloczek commented 2 years ago

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.

Here is list of modules installed in build env

```console 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 commented 2 years ago

Here is pytest output:

```console + 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 = 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 = , 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 = , 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 `. """ 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 = 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 `. """ 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 = 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 `. """ 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 `. :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 = 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 `. :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 = 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 = , 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 = , 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 = , 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 `. """ 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 = 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 = 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 = , 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 = , 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 `. """ 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 = 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 `. """ 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 = 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 `. """ 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 `. :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 = 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 `. :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 = 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 = , 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 = , 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 = , 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 `. """ 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 = 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 commented 2 years ago

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? 🤔