sarugaku / requirementslib

A tool for converting between pip-style and pipfile requirements - maintained by the pipenv team
MIT License
84 stars 28 forks source link

test_no_duplicate_egg_info fails with wrong egg_base #270

Open bnavigator opened 4 years ago

bnavigator commented 4 years ago
[   18s] __________________________ test_no_duplicate_egg_info __________________________
[   18s] 
[   18s]     def test_no_duplicate_egg_info():
[   18s]         """When the package has 'src' directory, do not write egg-info in base
[   18s]         dir."""
[   18s]         base_dir = vistir.compat.Path(os.path.abspath(os.getcwd())).as_posix()
[   18s]         r = Requirement.from_line("-e {}".format(base_dir))
[   18s]         egg_info_name = "{}.egg-info".format(r.name.replace("-", "_"))
[   18s]         distinfo_name = "{0}.dist-info".format(r.name.replace("-", "_"))
[   18s]     
[   18s]         def find_metadata(path):
[   18s]             metadata_names = [
[   18s]                 os.path.join(path, name) for name in (egg_info_name, distinfo_name)
[   18s]             ]
[   18s]             if not os.path.isdir(path):
[   18s]                 return None
[   18s]             pth = next(iter(pth for pth in metadata_names if os.path.isdir(pth)), None)
[   18s]             if not pth:
[   18s]                 pth = next(
[   18s]                     iter(
[   18s]                         pth
[   18s]                         for pth in os.listdir(path)
[   18s]                         if any(
[   18s]                             pth.endswith(md_ending)
[   18s]                             for md_ending in [".egg-info", ".dist-info", ".whl"]
[   18s]                         )
[   18s]                     ),
[   18s]                     None,
[   18s]                 )
[   18s]             return pth
[   18s]     
[   18s]         assert not find_metadata(base_dir)
[   18s]         assert not find_metadata(os.path.join(base_dir, "reqlib-metadata"))
[   18s]         assert not find_metadata(os.path.join(base_dir, "src", "reqlib-metadata"))
[   18s]         assert r.req.setup_info and os.path.isdir(r.req.setup_info.egg_base)
[   18s]         setup_info = r.req.setup_info
[   18s]         setup_info.get_info()
[   18s] >       assert (
[   18s]             find_metadata(setup_info.egg_base)
[   18s]             or find_metadata(setup_info.extra_kwargs["build_dir"])
[   18s]             or setup_info.get_egg_metadata()
[   18s]         )
[   18s] E       AssertionError: assert (None or None or None)

Maybe this is wrong:

(Pdb) print(setup_info.egg_base)
/home/abuild/rpmbuild/BUILD/requirementslib-1.5.13/reqlib-metadata

Full log with package version information: requirementslib_log.txt

frostming commented 3 years ago

Will you try again on the main branch?

bnavigator commented 3 years ago

Still an issue with 1.6.1:

>       assert (
            find_metadata(setup_info.egg_base)
            or find_metadata(setup_info.extra_kwargs["build_dir"])
            or setup_info.get_egg_metadata()
        )
E       AssertionError: assert (None or None or None)
E        +  where None = <function test_no_duplicate_egg_info.<locals>.find_metadata at 0x7f2a7cedfea0>('/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/reqlib-metadata')
E        +    where '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/reqlib-metadata' = SetupInfo(name=None, base_dir='/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1', _version=None, _requirements=frozen...ExitStack object at 0x7f2a7bd6ea20>, _finalizer=<finalize object at 0x7f2a7c1e6460; for 'SetupInfo' at 0x7f2a7bd1c498>).egg_base
E        +  and   None = <function test_no_duplicate_egg_info.<locals>.find_metadata at 0x7f2a7cedfea0>('/tmp/reqlib-build_3uy8y5o')
E        +  and   None = <bound method SetupInfo.get_egg_metadata of SetupInfo(name=None, base_dir='/home/abuild/rpmbuild/BUILD/requirementslib...xitStack object at 0x7f2a7bd6ea20>, _finalizer=<finalize object at 0x7f2a7c1e6460; for 'SetupInfo' at 0x7f2a7bd1c498>)>()
E        +    where <bound method SetupInfo.get_egg_metadata of SetupInfo(name=None, base_dir='/home/abuild/rpmbuild/BUILD/requirementslib...xitStack object at 0x7f2a7bd6ea20>, _finalizer=<finalize object at 0x7f2a7c1e6460; for 'SetupInfo' at 0x7f2a7bd1c498>)> = SetupInfo(name=None, base_dir='/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1', _version=None, _requirements=frozen...ExitStack object at 0x7f2a7bd6ea20>, _finalizer=<finalize object at 0x7f2a7c1e6460; for 'SetupInfo' at 0x7f2a7bd1c498>).get_egg_metadata

tests/unit/test_setup_info.py:85: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB post_mortem (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/unit/test_setup_info.py(85)test_no_duplicate_egg_info()
-> assert (
(Pdb) p setup_info.egg_base
'/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/reqlib-metadata'
(Pdb) 
bnavigator commented 3 years ago

More of setup_info is broken:


[   21s] =================================== FAILURES ===================================
[   21s] ________________________ test_local_req[test_artifact0] ________________________
[   21s] 
[   21s] test_artifact = PosixPath('/tmp/pytest-of-abuild/pytest-21/test_local_req_test_artifact0_0/environ_config')
[   21s] 
[   21s]     @pytest.mark.skipif(os.name == "nt", reason="Building this is broken on windows")
[   21s]     @pytest.mark.parametrize(
[   21s]         "test_artifact",
[   21s]         [
[   21s]             {"name": "environ_config", "as_artifact": False},
[   21s]             {"name": "environ_config", "as_artifact": True},
[   21s]         ],
[   21s]         indirect=True,
[   21s]     )
[   21s]     def test_local_req(test_artifact):
[   21s]         r = Requirement.from_line(test_artifact.as_posix())
[   21s]         assert r.name.replace("_", "-") == "environ-config"
[   21s]         setup_dict = r.req.setup_info.as_dict()
[   21s] >       assert sorted(list(setup_dict.get("requires").keys())) == ["attrs"]
[   21s] E       AttributeError: 'NoneType' object has no attribute 'keys'
[   21s] 
[   21s] tests/unit/test_setup_info.py:25: AttributeError
[   21s] ________________________ test_local_req[test_artifact1] ________________________
[   21s] 
[   21s] test_artifact = PosixPath('/tmp/pytest-of-abuild/pytest-21/test_local_req_test_artifact1_0/18.2.0.zip')
[   21s] 
[   21s]     @pytest.mark.skipif(os.name == "nt", reason="Building this is broken on windows")
[   21s]     @pytest.mark.parametrize(
[   21s]         "test_artifact",
[   21s]         [
[   21s]             {"name": "environ_config", "as_artifact": False},
[   21s]             {"name": "environ_config", "as_artifact": True},
[   21s]         ],
[   21s]         indirect=True,
[   21s]     )
[   21s]     def test_local_req(test_artifact):
[   21s]         r = Requirement.from_line(test_artifact.as_posix())
[   21s] >       assert r.name.replace("_", "-") == "environ-config"
[   21s] E       AttributeError: 'NoneType' object has no attribute 'replace'
[   21s] 
[   21s] tests/unit/test_setup_info.py:23: AttributeError
[   21s] _________________ test_ast_parser_handles_repeated_assignments _________________
[   21s] 
[   21s] setup_py_dir = PosixPath('/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/fixtures/setup_py')
[   21s] 
[   21s]     def test_ast_parser_handles_repeated_assignments(setup_py_dir):
[   21s]         target = (
[   21s]             setup_py_dir.joinpath("package_with_repeated_assignments").absolute().as_posix()
[   21s]         )
[   21s]         r = Requirement.from_line(target)
[   21s]         setup_dict = r.req.setup_info.as_dict()
[   21s] >       assert setup_dict["name"] == "test-package-with-repeated-assignments"
[   21s] E       KeyError: 'name'
[   21s] 
[   21s] tests/unit/test_setup_info.py:234: KeyError
[   21s] ______________________ test_ast_parser_handles_exceptions ______________________
[   21s] 
[   21s] self = <[AttributeError("'Requirement' object has no attribute 'name'") raised in repr()] Requirement object at 0x7fbabb3a2670>
[   21s] requirement_string = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     def __init__(self, requirement_string):
[   21s]         # type: (str) -> None
[   21s]         try:
[   21s] >           req = REQUIREMENT.parseString(requirement_string)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/packaging/requirements.py:113: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] self = {stringStart Combine:({W:(abcd...) [{W:(abcd...) | {[W:(-_.)]... W:(abcd...)}}]...}) [{Suppress:("[") [{Combine:({W:(a...tation" | "python_implementation" | "extra"} | {quoted string, starting with ' ending with ' | qu Empty}}]}} stringEnd}
[   21s] instring = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] parseAll = False
[   21s] 
[   21s]     def parseString(self, instring, parseAll=False):
[   21s]         """
[   21s]         Execute the parse expression with the given string.
[   21s]         This is the main interface to the client code, once the complete
[   21s]         expression has been built.
[   21s]     
[   21s]         Returns the parsed data as a :class:`ParseResults` object, which may be
[   21s]         accessed as a list, or as a dict or object with attributes if the given parser
[   21s]         includes results names.
[   21s]     
[   21s]         If you want the grammar to require that the entire input string be
[   21s]         successfully parsed, then set ``parseAll`` to True (equivalent to ending
[   21s]         the grammar with ``StringEnd()``).
[   21s]     
[   21s]         Note: ``parseString`` implicitly calls ``expandtabs()`` on the input string,
[   21s]         in order to report proper column numbers in parse actions.
[   21s]         If the input string contains tabs and
[   21s]         the grammar uses parse actions that use the ``loc`` argument to index into the
[   21s]         string being parsed, you can ensure you have a consistent view of the input
[   21s]         string by:
[   21s]     
[   21s]         - calling ``parseWithTabs`` on your grammar before calling ``parseString``
[   21s]           (see :class:`parseWithTabs`)
[   21s]         - define your parse action using the full ``(s, loc, toks)`` signature, and
[   21s]           reference the input string using the parse action's ``s`` argument
[   21s]         - explictly expand the tabs in your input string before calling
[   21s]           ``parseString``
[   21s]     
[   21s]         Example::
[   21s]     
[   21s]             Word('a').parseString('aaaaabaaa')  # -> ['aaaaa']
[   21s]             Word('a').parseString('aaaaabaaa', parseAll=True)  # -> Exception: Expected end of text
[   21s]         """
[   21s]         ParserElement.resetCache()
[   21s]         if not self.streamlined:
[   21s]             self.streamline()
[   21s]             # ~ self.saveAsList = True
[   21s]         for e in self.ignoreExprs:
[   21s]             e.streamline()
[   21s]         if not self.keepTabs:
[   21s]             instring = instring.expandtabs()
[   21s]         try:
[   21s]             loc, tokens = self._parse(instring, 0)
[   21s]             if parseAll:
[   21s]                 loc = self.preParse(instring, loc)
[   21s]                 se = Empty() + StringEnd()
[   21s]                 se._parse(instring, loc)
[   21s]         except ParseBaseException as exc:
[   21s]             if ParserElement.verbose_stacktrace:
[   21s]                 raise
[   21s]             else:
[   21s]                 # catch and re-raise exception from here, clearing out pyparsing internal stack trace
[   21s]                 if getattr(exc, '__traceback__', None) is not None:
[   21s]                     exc.__traceback__ = self._trim_traceback(exc.__traceback__)
[   21s] >               raise exc
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/pyparsing.py:1955: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] self = W:(abcd...)
[   21s] instring = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] loc = 0, doActions = True
[   21s] 
[   21s]     def parseImpl(self, instring, loc, doActions=True):
[   21s]         result = self.re_match(instring, loc)
[   21s]         if not result:
[   21s] >           raise ParseException(instring, loc, self.errmsg, self)
[   21s] E           pyparsing.ParseException: Expected W:(abcd...), found '/'  (at char 0), (line:1, col:1)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/pyparsing.py:3250: ParseException
[   21s] 
[   21s] During handling of the above exception, another exception occurred:
[   21s] 
[   21s] self = <Line (editable=False, name=None, path=None, uri=None, extras=(), markers=None, vcs=None, specifier=None, pyproject=None, pyproject_requires=None, pyproject_backend=None, ireq=None)>
[   21s] 
[   21s]     def _parse_name_from_line(self):
[   21s]         # type: () -> Optional[STRING_TYPE]
[   21s]         if not self.is_named:
[   21s]             pass
[   21s]         try:
[   21s] >           self._requirement = init_requirement(self.line)
[   21s] 
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:966: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] name = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     def init_requirement(name):
[   21s]         # type: (AnyStr) -> TRequirement
[   21s]     
[   21s]         if not isinstance(name, str):
[   21s]             raise TypeError("must supply a name to generate a requirement")
[   21s]         from pkg_resources import Requirement
[   21s]     
[   21s] >       req = Requirement.parse(name)
[   21s] 
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/utils.py:197: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] s = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     @staticmethod
[   21s]     def parse(s):
[   21s] >       req, = parse_requirements(s)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/pkg_resources/__init__.py:3139: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] strs = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     def parse_requirements(strs):
[   21s]         """Yield ``Requirement`` objects for each specification in `strs`
[   21s]     
[   21s]         `strs` must be a string, or a (possibly-nested) iterable thereof.
[   21s]         """
[   21s]         # create a steppable iterator, so we can handle \-continuations
[   21s]         lines = iter(yield_lines(strs))
[   21s]     
[   21s]         for line in lines:
[   21s]             # Drop comments -- a hash without a space may be in a URL.
[   21s]             if ' #' in line:
[   21s]                 line = line[:line.find(' #')]
[   21s]             # If there is a line continuation, drop it, and append the next line.
[   21s]             if line.endswith('\\'):
[   21s]                 line = line[:-2].strip()
[   21s]                 try:
[   21s]                     line += next(lines)
[   21s]                 except StopIteration:
[   21s]                     return
[   21s] >           yield Requirement(line)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/pkg_resources/__init__.py:3084: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] self = <[AttributeError("'Requirement' object has no attribute 'name'") raised in repr()] Requirement object at 0x7fbabb3a2670>
[   21s] requirement_string = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     def __init__(self, requirement_string):
[   21s]         """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
[   21s] >       super(Requirement, self).__init__(requirement_string)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/pkg_resources/__init__.py:3094: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] self = <[AttributeError("'Requirement' object has no attribute 'name'") raised in repr()] Requirement object at 0x7fbabb3a2670>
[   21s] requirement_string = '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s]     def __init__(self, requirement_string):
[   21s]         # type: (str) -> None
[   21s]         try:
[   21s]             req = REQUIREMENT.parseString(requirement_string)
[   21s]         except ParseException as e:
[   21s] >           raise InvalidRequirement(
[   21s]                 'Parse error at "{0!r}": {1}'.format(
[   21s]                     requirement_string[e.loc : e.loc + 8], e.msg
[   21s]                 )
[   21s]             )
[   21s] E           packaging.requirements.InvalidRequirement: Parse error at "'/home/ab'": Expected W:(abcd...)
[   21s] 
[   21s] /usr/lib/python3.9/site-packages/packaging/requirements.py:115: InvalidRequirement
[   21s] 
[   21s] During handling of the above exception, another exception occurred:
[   21s] 
[   21s] artifact_dir = PosixPath('/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts')
[   21s] 
[   21s]     def test_ast_parser_handles_exceptions(artifact_dir):
[   21s]         path = artifact_dir.joinpath("git/pyinstaller")
[   21s] >       r = Requirement.from_line(path.as_posix())
[   21s] 
[   21s] tests/unit/test_setup_info.py:240: 
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:2674: in from_line
[   21s]     parsed_line = Line(line)
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:171: in __init__
[   21s]     self.parse()
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:1304: in parse
[   21s]     self.parse_name()
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:1027: in parse_name
[   21s]     name = self._parse_name_from_line()
[   21s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   21s] 
[   21s] self = <Line (editable=False, name=None, path=None, uri=None, extras=(), markers=None, vcs=None, specifier=None, pyproject=None, pyproject_requires=None, pyproject_backend=None, ireq=None)>
[   21s] 
[   21s]     def _parse_name_from_line(self):
[   21s]         # type: () -> Optional[STRING_TYPE]
[   21s]         if not self.is_named:
[   21s]             pass
[   21s]         try:
[   21s]             self._requirement = init_requirement(self.line)
[   21s]         except Exception:
[   21s] >           raise RequirementError(
[   21s]                 "Failed parsing requirement from {0!r}".format(self.line)
[   21s]             )
[   21s] E           requirementslib.exceptions.RequirementError: Failed parsing requirement from '/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/artifacts/git/pyinstaller'
[   21s] 
[   21s] ../../BUILDROOT/python-requirementslib-1.6.1-0.x86_64/usr/lib/python3.9/site-packages/requirementslib/models/requirements.py:968: RequirementError
[   21s] ____________________ test_read_requirements_with_list_comp _____________________
[   21s] 
[   21s] setup_py_dir = PosixPath('/home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/fixtures/setup_py')
[   21s] 
[   21s]     def test_read_requirements_with_list_comp(setup_py_dir):
[   21s]         req = Requirement.from_line(
[   21s]             f"-e {(setup_py_dir / 'package_with_setup_with_list_comp').as_posix()}"
[   21s]         )
[   21s]         setup_info = req.req.setup_info.as_dict()
[   21s] >       assert sorted(setup_info["requires"]) == ["requests"]
[   21s] E       KeyError: 'requires'
[   21s] 
[   21s] tests/unit/test_setup_info.py:257: KeyError
[   21s] =============================== warnings summary ===============================
[   21s] tests/conftest.py:49
[   21s]   /home/abuild/rpmbuild/BUILD/requirementslib-1.6.1/tests/conftest.py:49: RuntimeWarning: Failed connecting to internet: http://clients3.google.com/generate_204
[   21s]     warnings.warn("Failed connecting to internet: {0}".format(url), RuntimeWarning)
[   21s] 
[   21s] -- Docs: https://docs.pytest.org/en/stable/warnings.html
[   21s] =========================== short test summary info ============================
[   21s] FAILED tests/unit/test_setup_info.py::test_local_req[test_artifact0] - Attrib...
[   21s] FAILED tests/unit/test_setup_info.py::test_local_req[test_artifact1] - Attrib...
[   21s] FAILED tests/unit/test_setup_info.py::test_ast_parser_handles_repeated_assignments
[   21s] FAILED tests/unit/test_setup_info.py::test_ast_parser_handles_exceptions - re...
[   21s] FAILED tests/unit/test_setup_info.py::test_read_requirements_with_list_comp
[   21s] =========== 5 failed, 162 passed, 20 deselected, 1 warning in 11.65s ===========