Make sure python directive returns a string
ClosedPublic

Authored by lbrabec on May 22 2014, 9:46 AM.

Details

Summary

Quick fix for T95 was introduced in D47, this is proper one. Callable task method must now return string.

Test Plan

$ python runtask.py -i xchat-2.8.8-21.fc20 -t koji_build -a x86_64 ../task-rpmlint/rpmlint.yml
$ python runtask.py -i tigervnc-1.3.0-14.fc20 -t koji_build -a x86_64 ../task-examplebodhi/examplebodhi.yml

Diff Detail

Repository
rLTRN libtaskotron
Lint
Lint Skipped
Unit
Unit Tests Skipped

I'm not sure I understand the reason for enforcing the return of a single string from the python directive other than making sure it's consistent.

Can you elaborate a bit on why enforcing a single string return is the best solution here when other directives return non-strings?

Tim, thanks for the comment. I thought about it and I realized several important things.

My initial motivation was to make check output consistent and my reasoning was like this:

  1. Checks are expected to return TAP.
  2. TAP is a string. It can't be a list, it doesn't make much sense. If it were a list, should we simply join it by newlines? Or would it be a list of individual TAP results, so that we would have to join them in a proper TAP manner (delimiters and such) and then generate the TAP header? It's too complicated, too much to explain, too much to document, without any clear benefit. Therefore TAP is a string. Simple, expected.
  3. Checks are run through the python directive.
  4. Outcome: The python directive must return a string and we should enforce it.

However, I realized:
a) We currently have no documentation at all regarding directive output. Different directives can return a range variety of data, and there's no way to knowing what data unless you read the source code. We should put return data documentation into the directive docstring in the very least.
b) The check doesn't have to be executed by the python directive. That is not true at the moment, but can/should easily become true in the future (bash checks, for example).
c) The python directives doesn't have to execute checks. It can be some other code, for example some environment preparation scripts (and then, in another python directive can the actual check be run).
d) We currently print to stdout anything that we find in Runner.working_data and assume they are check results. That's a bit shortsighted, because working_data should be used for arbitrary data transfer, not just check results. We will need to change that as well and find a better way to distinguishing check results from other data.

This is just a food for thought at the moment, we won't solve all of that here, we will need to file individual tickets for these issue. Here, I think we could start with the basics:

  1. This patch should be modified to allow str and None values as python directive output. That covers the most basic needs (TAP output and not-a-check python script).
  2. The python directive's docstring should be adjusted to reflect that.

If you agree with the core problems mentioned, I would create individual tickets for them. This patch might get reverted once we solve them, but in the mean time, it would ensure consistent and valid check output. What do you think?

kparal retitled this revision from Proper fix for T95 to Make sure python directive returns a string.May 28 2014, 2:21 PM
tflink requested changes to this revision.May 30 2014, 3:53 PM

TAP is a string. It can't be a list, it doesn't make much sense. If it were a list, should we simply join it by newlines? Or would it be a list of individual TAP results, so that we would have to join them in a proper TAP manner (delimiters and such) and then generate the TAP header? It's too complicated, too much to explain, too much to document, without any clear benefit. Therefore TAP is a string. Simple, expected.
Checks are run through the python directive.
Outcome: The python directive must return a string and we should enforce it.

OK, that makes sense for the time being, at least. Are our reporting directives capable of understanding multiple TAP results concatenated together? Do we currently have any checks that output multiple TAP streams? I can't think of any off the top of my head.

a) We currently have no documentation at all regarding directive output. Different directives can return a range variety of data, and there's no way to knowing what data unless you read the source code. We should put return data documentation into the directive docstring in the very least.

Yeah, that's a problem. I think that it's partially covered by T183 and T142 but there's a lot of stuff not covered by those two tickets.

b) The check doesn't have to be executed by the python directive. That is not true at the moment, but can/should easily become true in the future (bash checks, for example).
c) The python directives doesn't have to execute checks. It can be some other code, for example some environment preparation scripts (and then, in another python directive can the actual check be run).
d) We currently print to stdout anything that we find in Runner.working_data and assume they are check results. That's a bit shortsighted, because working_data should be used for arbitrary data transfer, not just check results. We will need to change that as well and find a better way to distinguishing check results from other data.

These are good points. Thanks for bringing them up.

This is just a food for thought at the moment, we won't solve all of that here, we will need to file individual tickets for these issue. Here, I think we could start with the basics:

Yeah, I think that we need to spend some time making sure that our internals are at least reasonably consistent and documented. I suspect that the directive docs will go a ways toward making this better but that's getting a bit off topic for a code review :)

This patch should be modified to allow str and None values as python directive output. That covers the most basic needs (TAP output and not-a-check python script). The python directive's docstring should be adjusted to reflect that.

Agreed. @lbrabec, would ypu update the revision to do this?

If you agree with the core problems mentioned, I would create individual tickets for them. This patch might get reverted once we solve them, but in the mean time, it would ensure consistent and valid check output. What do you think?

Sounds like a plan to me.

This revision now requires changes to proceed.May 30 2014, 3:53 PM
lbrabec updated this revision to Diff 340.Jun 2 2014, 9:56 AM
lbrabec edited the test plan for this revision. (Show Details)
  • python directive can return string or none
lbrabec updated this revision to Diff 341.Jun 2 2014, 10:02 AM
  • fixing bad commit
kparal requested changes to this revision.Jun 2 2014, 10:22 AM

Are all of those test_python_directive.py changes still necessary when we allowed None to be returned?

Can you please add a new unit tests that verifies that TaskotronDirectiveError gets raised when you try to return something else than None and basestring? (Be sure to also test corner cases like an empty string, or an empty list). Thanks.

libtaskotron/directives/python_directive.py
69

You should use if output is not None. Otherwise an empty list (for example) would not get checked.

70–73

This could easily fit on two lines, but I don't want to talk too much into your code structuring habits :-) What interests me, though, are the redundant str() calls I see lately. If there was just "%s" % output and output could be anything, then yes, if output was a tuple, then it could break the formatting. But since you already call type() on it and you know what gets returned (a type), you no longer need to manually cast it to string, that's what %s does for you.

Just a nitpick.

libtaskotron/runner.py
200–203

It seems your formatting is somehow broken (no whitespace between variable name and value?).

I'd suggest a bit more readable approach (not tested):

log.info('Check execution finished. Showing stored variables:')
for name, value in task_runner.working_data.items():
    log.info("%${s}:\n%s" % (name, value))
This revision now requires changes to proceed.Jun 2 2014, 10:22 AM
lbrabec updated this revision to Diff 342.Jun 2 2014, 11:24 AM
  • new unit tests and code polishing
kparal accepted this revision.Jun 3 2014, 9:16 AM
kparal added inline comments.
libtaskotron/runner.py
203

Thanks for correcting my typo :-)

lbrabec closed this revision.Jun 3 2014, 9:27 AM
lbrabec updated this revision to Diff 345.

Closed by commit rLTRNd4de0b2847ec (authored by @lbrabec).