madpah/requirements-parser

Failing tests on the master branch

Closed this issue · 7 comments

belak commented

The tests on the master branch are currently failing.

% py.test                                                                                              x [master]
================================================================= test session starts =================================================================
platform linux -- Python 3.5.2, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /home/belak/requirements-parser, inifile: 
collected 23 items 

tests/test_parser.py .......F.........F.....

====================================================================== FAILURES =======================================================================
______________________________________________________________ test_requirement_files[7] ______________________________________________________________

s = <_io.TextIOWrapper name='/home/belak/requirements-parser/tests/reqfiles/illustrative_requirements.txt' mode='r' encoding='UTF-8'>
expected = [{'editable': True, 'extras': [], 'line': '-e git+https://github.com/davidfischer/requirements-parser.git#egg=requirem...'local_file': False, ...}, {'editable': False, 'extras': ['pdf'], 'line': 'DocParser [PDF]', 'local_file': False, ...}]

    @fancy
    def check(s, expected):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
>           assert_equal(listify([dict(r) for r in parse(s)]), expected)

tests/test_parser.py:41: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib64/python3.5/unittest/case.py:820: in assertEqual
    assertion_func(first, second, msg=msg)
/usr/lib64/python3.5/unittest/case.py:1018: in assertListEqual
    self.assertSequenceEqual(list1, list2, msg, seq_type=list)
/usr/lib64/python3.5/unittest/case.py:1000: in assertSequenceEqual
    self.fail(msg)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <nose.tools.trivial.Dummy testMethod=nop>
msg = "Lists differ: [{'ex[21 chars]t', 'line': '-e git+https://github.com/davidfi[842 chars]one}] != [{'ex[21 chars]t', 'na...Django', 'path': None, 'specs': [[144 chars]True}\n\nDiff is 1150 characters long. Set self.maxDiff to None to see it."

    def fail(self, msg=None):
        """Fail immediately, with the given message."""
>       raise self.failureException(msg)
E       AssertionError: Lists differ: [{'ex[21 chars]t', 'line': '-e git+https://github.com/davidfi[842 chars]one}] != [{'ex[21 chars]t', 'name': 'requirements', 'path': None, 'spe[842 chars]rue}]
E       
E       First differing element 1:
E       {'ext[19 chars]ne, 'line': 'Django >=1.5, <1.6', 'specifier':[144 chars]None}
E       {'ext[19 chars]ne, 'name': 'Django', 'path': None, 'specs': [[144 chars]True}
E       
E       Diff is 1150 characters long. Set self.maxDiff to None to see it.

/usr/lib64/python3.5/unittest/case.py:665: AssertionError
_____________________________________________________________ test_requirement_files[17] ______________________________________________________________

s = <_io.TextIOWrapper name='/home/belak/requirements-parser/tests/reqfiles/specs_1.txt' mode='r' encoding='UTF-8'>
expected = [{'editable': False, 'extras': [], 'line': 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1', 'local_file': False, ...}]

    @fancy
    def check(s, expected):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
>           assert_equal(listify([dict(r) for r in parse(s)]), expected)

tests/test_parser.py:41: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib64/python3.5/unittest/case.py:820: in assertEqual
    assertion_func(first, second, msg=msg)
/usr/lib64/python3.5/unittest/case.py:1018: in assertListEqual
    self.assertSequenceEqual(list1, list2, msg, seq_type=list)
/usr/lib64/python3.5/unittest/case.py:1000: in assertSequenceEqual
    self.fail(msg)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <nose.tools.trivial.Dummy testMethod=nop>
msg = "Lists differ: [{'ex[20 chars]ne, 'line': 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a[222 chars]one}] != [{'ex[20 chars]ne, 'na...        ^     --\n\n+             ['==', '2.4c1']],\n?               ^^    ++++\n\n    'uri': None,\n    'vcs': None}]"

    def fail(self, msg=None):
        """Fail immediately, with the given message."""
>       raise self.failureException(msg)
E       AssertionError: Lists differ: [{'ex[20 chars]ne, 'line': 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a[222 chars]one}] != [{'ex[20 chars]ne, 'name': 'PickyThing', 'path': None, 'specs[222 chars]rue}]
E       
E       First differing element 0:
E       {'ext[19 chars]ne, 'line': 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a[221 chars]None}
E       {'ext[19 chars]ne, 'name': 'PickyThing', 'path': None, 'specs[221 chars]True}
E       
E         [{'editable': False,
E           'extras': [],
E           'line': 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1',
E           'local_file': False,
E           'name': 'PickyThing',
E           'path': None,
E           'revision': None,
E           'specifier': True,
E       -   'specs': [['==', '2.4c1'],
E       ?               ^^    ^ ^^^
E       
E       +   'specs': [['<', '1.6'],
E       ?               ^    ^ ^
E       
E       +             ['>', '1.9'],
E       +             ['!=', '1.9.6'],
E                     ['<', '2.0a0'],
E       -             ['<', '1.6'],
E       -             ['!=', '1.9.6'],
E       -             ['>', '1.9']],
E       ?               ^     --
E       
E       +             ['==', '2.4c1']],
E       ?               ^^    ++++
E       
E           'uri': None,
E           'vcs': None}]
belak commented

It looks like this might be related to the order of elements? But I'm not sure why it would only fail sometimes.

belak commented

Even with the fixes on master, I'm still running into problems with running the tests locally.

It looks like this is a breaking change in setuptools (pkg_resources.Requirement.parse). It is somewhat of an undocumented API.

from pkg_resources import Requirement
req = Requirement.parse('PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1')
req.specs
# [('!=', '1.9.6'), ('<', '2.0a0'), ('>', '1.9'), ('==', '2.4c1'), ('<', '1.6')]
# The output order is not deterministic (although it will be the same until you restart the interpreter)

Previously, pkg_resources would return them in the order they came.

Ok, it looks like setuptools started relying on a library called packaging. This library stores the specifiers into a set.

I see a couple interesting things here. Firstly, packaging is probably a great library to rely on instead of setuptools' undocumented API!

fruch commented

So fix the tests to use sets also ?

@davidfischer @belak proposed fix in #31