Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Changed for bytes/str conversion lines not hit in test_isoparser #833

Closed
wants to merge 6 commits into from

Conversation

jramacha
Copy link

@jramacha jramacha commented Oct 30, 2018

Summary of changes

@pganssle mentioned some branches were not hit in test_isoparser.py. Ran the test and found that the test weren't hitting the is instance(param, six.text_type) for python2.7 , because the string value returned from strftime was not a unicode string, so converted that to unicode and made sure the test were hitting both the branches. And test weren't hitting the isinstance(param, bytes) for python3+ because the string value returned from strftime always failed that check as it was unicode string. So added a line to encode that string to ascii and made sure the test hit the other branch.

Also added #pragma: no cover to lines not covered.

Closes #776

Copy link
Member

@pganssle pganssle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your attempt to fix this issue, but as it stands this PR currently adds many more issues and doesn't solve the original problems.

To get it into shape, please address my inline comments. The big picture items are:

  • Revert your changes to test_parse_isodate
  • Revert your changes to test_isotime and add the correct fix (changing time_val to tstr in the isinstance checks)
  • Remove the spurious # pragma: nocover statements on already-covered tests
  • For unconditional xfail tests (not the one that only fails on Python 3), change it so that only the def line has # pragma: nocover.

As a guide, take a look at the current coverage report. Do not add # pragma: nocover to anything where the line is already green.

Thanks!

d_str = d_str.encode('ascii')
elif isinstance(d_str, bytes) and not as_bytes:
d_str = d_str.decode('ascii')
if six.PY2:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer it if this were written in polyglot style, so nothing that makes explicit reference to six.PY2.

That said, this is the wrong thing to do. The original code block was this (I've annotated with comments to make it clear what's happening):

if isinstance(d_str, six.text_type) and as_bytes:
    # If d_str is str/unicode, convert it into bytes
    d_str = d_str.encode('ascii')
elif isinstance(d_str, bytes) and not as_bytes:
    # If d_str is bytes, convert it to str/unicode
    d_str = d_str.decode('ascii')

The problem is that I'm expecting to run the same code with as_bytes=True and as_bytes=False, which means that whatever d_str is, it should have to be converted to the other thing half the time. In Python 2 I expect it to be bytes and in Python 3 I expect it to be str, so both of these branches should already be hit.

unicode(b'example') is the wrong way to convert from bytes to string, the correct way is b'example'.encode(), which is what I'm already doing.

Anyway, either something has changed since the original issue was raised or I made a mistake originally, because it seems like these lines are indeed covered, and only the later lines (with time_val) are having the coverage problem, so these changes can be removed entirely.

@@ -399,7 +407,7 @@ def test_parse_isodate(d, dt_fmt, as_bytes):
('2014-04-19T', ValueError), # Unknown components
])
def test_isodate_raises(isostr, exception):
with pytest.raises(exception):
with pytest.raises(exception): #pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be covered, it is a normal test that is testing that these things raise errors.

tstr = tstr.encode('ascii')
elif isinstance(time_val, bytes) and not as_bytes:
tstr = tstr.decode('ascii')
if six.PY2:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the other changes, this is not the correct approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the problem is that in the original code, I was using:

if isinstance(time_val, six.text_type) and as_bytes:
    ...

But what I wanted was:

if isinstance(tstr, six.text_type) and as_bytes:
    ...

Because time_val is the time input, not the output of time_val.strftime (which will either be bytes or str depending on the Python version).

@@ -501,16 +516,16 @@ def test_isotime_midnight(isostr):
])
def test_isotime_raises(isostr, exception):
iparser = isoparser()
with pytest.raises(exception):
with pytest.raises(exception): #pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a normal test, please remove the #pragma: nocover

iparser.parse_isotime(isostr)


@pytest.mark.xfail()
@pytest.mark.xfail() #pragma: no cover
@pytest.mark.parametrize('isostr,exception', [
('14:3015', ValueError), # Inconsistent separator use
('201202', ValueError) # Invalid ISO format
])
def test_isotime_raises_xfail(isostr, exception):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_isotime_raises_xfail(isostr, exception):
def test_isotime_raises_xfail(isostr, exception): # pragma: nocover

This is the only line in this function that needs # pragma; nocover. The pragma goes after the function signature line on each of the xfail tests, and not in the body or on the decorator.

dt = datetime(2017, 12, 6, 12, 30, 45)
dt_str = dt.isoformat(sep=str('T'))
@pytest.mark.xfail(six.PY3, reason="Fails on Python 3 only") #pragma: no cover
def test_isoparser_byte_sep(): #pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole function does not need # pragma: nocover because it is indeed already covered by the Python 2 tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can xfails be made strict? Makes sure we get alerted if something is accidentally fixed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are already strict. It's configured globally in the pytest section of setup.cfg

@@ -286,15 +286,15 @@ def test_iso_with_sep_raises(sep_act, valid_sep, exception):
parser.isoparse(isostr)


@pytest.mark.xfail()
@pytest.mark.xfail() #pragma: no cover
@pytest.mark.parametrize('isostr,exception', [
('20120425T01:2000', ValueError), # Inconsistent time separators
])
def test_iso_raises_failing(isostr, exception):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_iso_raises_failing(isostr, exception):
def test_iso_raises_failing(isostr, exception): # pragma: nocover

Only this line needs # pragma: nocover. As I mention below, you can mark an entire function as not covered by a single pragma on the def line.

@pganssle pganssle closed this Feb 22, 2019
@fhuang5 fhuang5 mentioned this pull request Feb 23, 2019
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants