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

Filter out tests with no programming environments #319

Merged
merged 9 commits into from
Jun 15, 2018

Conversation

teojgo
Copy link
Contributor

@teojgo teojgo commented Jun 7, 2018

  • Create the corresponding unit test.

Fixes #244

* Create the corresponding unit test.
@codecov-io
Copy link

codecov-io commented Jun 7, 2018

Codecov Report

Merging #319 into master will increase coverage by 0.08%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #319      +/-   ##
==========================================
+ Coverage   91.18%   91.26%   +0.08%     
==========================================
  Files          67       67              
  Lines        7941     8005      +64     
==========================================
+ Hits         7241     7306      +65     
+ Misses        700      699       -1
Impacted Files Coverage Δ
unittests/test_utility.py 98.77% <100%> (+0.03%) ⬆️
reframe/utility/__init__.py 93.23% <100%> (+0.67%) ⬆️
unittests/test_cli.py 96.19% <100%> (+0.38%) ⬆️
reframe/utility/sanity.py 98.76% <100%> (+0.01%) ⬆️
reframe/frontend/cli.py 80.41% <100%> (+0.84%) ⬆️
unittests/test_sanity_functions.py 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 96d3a62...0d14066. Read the comment docs.

for e in options.prgenv) else None,
lambda c: c if (c.valid_prog_environs
and all(c.supports_environ(e)
for e in options.prgenv)) else None,
Copy link
Contributor

Choose a reason for hiding this comment

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

This lambda gets a bit too complicated. Since this operation is quite useful, I suggest writing a function in utility doing that thing:

def allx(iterable):
    # we should check here specifically if `iterable` is actually an iterable, as real all() does
    if not iterable:
        return False

    return all(iterable)

Would it also make sense to provide a deferrable version of this function in this PR, too?

* Create `allx` function in `reframe/utility/__init__.py`.

* Create the corresponding deferrable version of `allx`.

* Create the unit tests for the above functions.

* Use raw strings in some regular expressions to avoid warnings.
@@ -116,6 +117,16 @@ def all(iterable):
return builtins.all(iterable)


@deferrable
def allx(iterable):
"""Replacement for the :func:`allx() <reframe.utility.allx>` function.
Copy link
Contributor

Choose a reason for hiding this comment

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

The documentation of reframe.utility is not public, so you may not refer to it here.

@@ -54,6 +56,28 @@ def import_module_from_file(filename):
return importlib.import_module(module_name)


def allx(iterable):
"""Return ``True`` if all elements of the `iterable` are true. If
iterable is empty or ``None`` return ``False``.
Copy link
Contributor

Choose a reason for hiding this comment

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

  • I would phrase this different to stress the connection with the builtin all(): Same as the built-in all, except that it returns False if iterable is empty.
  • This function must be fully equivalent with the built-in all() if iterable is not empty, which means, we should raise TypeError if the argument is None. Pay attention to have fully compatible behaviour.
  • There are several documentation formatting issues here:
    • Double backquotes must be used for citing function arguments, here iterable.
    • None, True and False must be formatted as :class:`None` , :class:`True` etc.

first_item = next(iterable)
return all(itertools.chain([first_item], iterable))
except StopIteration:
return False
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't understand all this fuss here. Why a check of iterable against collections.abc.Iterable wouldn't just work?

>>> import collections
>>> isinstance(range(0), collections.abc.Iterable)
True
>>>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we do not want to accept empty generators. Is there any other way to check that a generator is empty?

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean by "empty generator"? A generator is a generator, i.e., an iterable, even if it doesn't produce any values. Your unit tests should pass fine using my proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I mean a generator like (i for i in []) if it is passed to allx how can I check that there are no elements and return False?

Copy link
Contributor

@vkarak vkarak Jun 12, 2018

Choose a reason for hiding this comment

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

Now, I get what you are trying to do. The comment above the code is really misleading... Please change it with sth more precise!

except StopIteration:
return False

if not iterable:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not enough. If iterable is None, we should raise a TypeError as all() does.

self.assertFalse(expr3)
self.assertFalse(expr4)
self.assertFalse(expr5)
self.assertTrue(expr6)
Copy link
Contributor

Choose a reason for hiding this comment

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

You can combine these assertions with the expressions above.

expr3 = sn.allx([])
expr4 = sn.allx(None)
expr5 = sn.allx(i for i in [])
expr6 = sn.allx(i for i in [1])
Copy link
Contributor

Choose a reason for hiding this comment

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

I would use ranges here.

if isinstance(iterable, types.GeneratorType):
try:
first_item = next(iterable)
return all(itertools.chain([first_item], iterable))
Copy link
Contributor

Choose a reason for hiding this comment

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

Better put this in the else block of the try/except. Also rename first_item to first or head.

teojgo and others added 3 commits June 12, 2018 13:55
- Rationale on special treatment of generators in allx.
- Document the sanity function correctly.
- Correct line splits.
@teojgo
Copy link
Contributor Author

teojgo commented Jun 14, 2018

@jenkins-cscs retry all

Copy link
Contributor

@vkarak vkarak left a comment

Choose a reason for hiding this comment

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

@teojgo @victorusu I think there is a fundamental problem with this PR:

On master, this

./reframe.py -C config/cscs.py -c cscs-checks/ -R -l

gives a whole listing of the tests, whereas here it gives nothing!

@teojgo
Copy link
Contributor Author

teojgo commented Jun 14, 2018

@victorusu what should be the expected behavior when a check has an empty prgenv list and we also do not specify any particular prgenv to ReFrame?

@vkarak
Copy link
Contributor

vkarak commented Jun 14, 2018

@teojgo @victorusu The logical thing to do would be to print the test if it supports any programming environment, i.e., valid_prog_environs is not empty.

# Here we also check that the valid_prog_environs of the check
# is an iterable and not empty
filter_func = lambda c: c if util.allx(
c.valid_prog_environs) else None
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest replacing the lambdas altogether here in favour of a closure:

def filter_prgenv(c):
    if options.prgenv:
        return util.allx(c.supports_environ(e) for e in options.prgenv)
    else:
        return bool(c.valid_prog_environs)

@vkarak vkarak changed the title Add extra filter for empty prg environs Filter out tests with no programming environments Jun 15, 2018
@vkarak vkarak merged commit f87f557 into master Jun 15, 2018
@vkarak vkarak deleted the enhancement/exclude_empty_prgenvs branch June 15, 2018 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants