0

The following code fails to run, but if I remove the line "datafile = sys.argv[1]" it works fine. I invoke the script as:

generateTests.py full-path-to-file

The error message is below the code sample. Could someone explain what is wrong with doing this?

#!/usr/bin/python
import sys
import unittest
import xmlrunner

mydata = [["VectorAdd", "56"],["MatrixMul", "101"]]

class TestWithDataFiles(unittest.TestCase):
    def setUp(self):
        print("Initializing...")


    @classmethod
    def setUpClass(cls):
        # Now call unittest version
        super(TestWithDataFiles, cls).setUpClass()
        print("Class setup...")
        datafile = sys.argv[1]

def myClass(TestWithDataFiles):
    @classmethod
    def setUpClass(cls):
        # Call TestWithDataFiles class setup first
        super(myClass, cls).setUpClass()

def test_genHSAILRunToBreakpoint(testData):
    def test_HSAILRunToBreakpoint(self):
        print("%s"%testData[0])
        print(self)
    return test_HSAILRunToBreakpoint

def test_genHSAILRunToTwoBreakpoints(testData):
    def test_HSAILRunToTwoBreakpoints(self):
        print("%s"%testData[1])
    return test_HSAILRunToTwoBreakpoints


if __name__ == '__main__':
    for testData in mydata:
        test_name = "test_HSAILRunToBreakpoint_%s"%testData[0]
        test = test_genHSAILRunToBreakpoint(testData)
        setattr(TestWithDataFiles, test_name, test)

        test_name = "test_HSAILRunToTwoBreakpoints_%s"%testData[0]
        test = test_genHSAILRunToTwoBreakpoints(testData)
        setattr(TestWithDataFiles, test_name, test)
    unittest.main(testRunner=xmlrunner.XMLTestRunner(output="testlog"))


python ~/bin/generateTests.py ~/.profile
Traceback (most recent call last):
  File "/home/bgriffin/bin/generateTests.py", line 47, in <module>
    unittest.main(testRunner=xmlrunner.XMLTestRunner(output="testlog"))
  File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__
    self.parseArgs(argv)
  File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs
    self.createTests()
  File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests
    self.module)
  File "/usr/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute '/home/bgriffin/'

The following code modifications still fail. Note that I tried using both test_name and test in the suite.addTests call, both have the same behavior.

#!/usr/bin/python
import argparse
import sys
import unittest
import xmlrunner

mydata = [["VectorAdd", "56"],["MatrixMul", "101"]]

class TestWithDataFiles(unittedst.TestCase):
    def setUp(self):
        print("Initializing...")


    @classmethod
    def setUpClass(cls):
        # Now call unittest version
        super(TestWithDataFiles, cls).setUpClass()
        print("Class setup...")
        dataFile = "teswt"
        arg1 = sys.argv[1]
        print(arg1)

def myClass(TestWithDataFiles):
    @classmethod
    def setUpClass(cls):
        # Call TestWithDataFiles class setup first
        super(myClass, cls).setUpClass()

def test_genHSAILRunToBreakpoint(testData):
    def test_HSAILRunToBreakpoint(self):
        print("%s"%testData[0])
        print(self)
    return test_HSAILRunToBreakpoint

def test_genHSAILRunToTwoBreakpoints(testData):
    def test_HSAILRunToTwoBreakpoints(self):
        print("%s"%testData[1])
    return test_HSAILRunToTwoBreakpoints


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--useValgrind', help="run hsail-gdb through valgrind")
    parser.add_argument('--branch', action='store', type=str, default="main", help="perforce branch to run tests from")
    parser.add_argument('--datafiles', action='store', type=str, help="Comma separated list of test data files")
    args = parser.parse_args()
    print(args.datafiles)
    suite = unittest.TestSuite()

    for testData in mydata:
        test_name = "test_HSAILRunToBreakpoint_%s"%testData[0]
        test = test_genHSAILRunToBreakpoint(testData)
        setattr(TestWithDataFiles, test_name, test)
        suite.addTest(myClass(test))

        test_name = "test_HSAILRunToTwoBreakpoints_%s"%testData[0]
        test = test_genHSAILRunToTwoBreakpoints(testData)
        setattr(TestWithDataFiles, test_name, test)
        suite.addTest(myClass(test))

    results = xmlrunner.XMLTestRunner(output="testlog").run(suite)

python ~/bin/generateTests.py --datafiles ~/.profile/home/bgriffin/.profile
Traceback (most recent call last):
  File "/home/bgriffin/bin/generateTests.py", line 54, in <module>
    suite.addTest(myClass(test))
  File "/usr/lib/python2.7/unittest/suite.py", line 49, in addTest
    raise TypeError("{} is not callable".format(repr(test)))
TypeError: None is not callable
cspiral
  • 11
  • 3
  • 1
    `sys.argv` is a list composed of the command-line arguments, starting (`sys.argv[0]`) with the name of the program as invoked. If you invoke it without command-line arguments, why would you expect anything beyond `sys.argv[0]` to be populated? – Two-Bit Alchemist Nov 13 '15 at 19:00
  • 1
    @Two-BitAlchemist: But he did pass an argument. – BrenBarn Nov 13 '15 at 19:02
  • 1
    At one point in the question, you say you invoke it as `generateTests.py`, but in your code example it says `python ~/bin/generateTests.py ~/.profile` Which is it? – BrenBarn Nov 13 '15 at 19:04
  • @BrenBarn I do see the example at the bottom, but I took " I invoke the script as: `generateTests.py`" to mean "I encounter this problem with the `datafile = sys.argv[1]` when I don't pass arguments. Hopefully OP can clear up my confusion. – Two-Bit Alchemist Nov 13 '15 at 19:04
  • @Two-BitAlchemist: You're right, there is inconsistency in the question. We'll see if OP clarifies. – BrenBarn Nov 13 '15 at 19:05
  • So I played around some more and apparently it isn't the code line but my argument. Apparently python doesn't like me adding any options other than the ones it knows about? I only seem to see this issue when I dynamically create functions. I will try adding argparse, perhaps that will be better? – cspiral Nov 13 '15 at 19:21
  • I invoked with an argument, not without, I know better than to do that. – cspiral Nov 13 '15 at 19:23
  • Maybe I need to be clearer. Right now, it looks like the problem ISN'T with the line of code, but the actual command line parsing. unittest seems to be treating my filename, or some portion of it, as a module function or attribute name, rather than ignoring it. – cspiral Nov 13 '15 at 19:26
  • Does [this question](http://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script) help? If you don't want the argument you pass to be used by unittest, don't pass it when you call `unittest.main`. – BrenBarn Nov 13 '15 at 19:42
  • That question was helpful, but not enough. As I saw, unittest.main wants to control sys.argv. The following lets me specify my own command line, but the suite.addtest doesn't work. I am not sure whether I should use th "test_name" or the "test" variable with it, and both generate an error. I will add the code in the next comment – cspiral Nov 13 '15 at 20:18
  • 1
    The final solution is to call "del sys.argv[1:]" after parsing my arguments and before calling unittest.main – cspiral Nov 13 '15 at 20:52
  • @cspiral Seems like a decent enough solution all things considered. You can post and accept your own answer, if you like. I encourage it. – Two-Bit Alchemist Nov 13 '15 at 22:31

1 Answers1

0

The following was my final solution. I use argparse to define and parse the command line options, then delete all the sys.argv values except sys.argv[0], before calling unittest.main()

#!/usr/bin/python
import argparse
import sys
import unittest
import xmlrunner

mydata = [["VectorAdd", "56"],["MatrixMul", "101"]]

class TestWithDataFiles(unittest.TestCase):
    def setUp(self):
        print("Initializing...")


    @classmethod
    def setUpClass(cls):
        # Now call unittest version
        super(TestWithDataFiles, cls).setUpClass()
        print("Class setup...")

def myClass(TestWithDataFiles):
    @classmethod
    def setUpClass(cls):
        # Call TestWithDataFiles class setup first
        super(myClass, cls).setUpClass()

def test_genHSAILRunToBreakpoint(testData):
    def test_HSAILRunToBreakpoint(self):
        print("%s"%testData[0])
        print(self)
    return test_HSAILRunToBreakpoint

def test_genHSAILRunToTwoBreakpoints(testData):
    def test_HSAILRunToTwoBreakpoints(self):
        print("%s"%testData[1])
    return test_HSAILRunToTwoBreakpoints


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--useValgrind', help="run hsail-gdb through valgrind")
    parser.add_argument('--branch', action='store', type=str, default="main", help="perforce branch to run tests from")
    parser.add_argument('--datafiles', action='store', type=str, help="Comma separated list of test data files")
    args = parser.parse_args()
    print(args.datafiles)
    del sys.argv[1:]

    for testData in mydata:
        test_name = "test_HSAILRunToBreakpoint_%s"%testData[0]
        test = test_genHSAILRunToBreakpoint(testData)
        setattr(TestWithDataFiles, test_name, test)

        test_name = "test_HSAILRunToTwoBreakpoints_%s"%testData[0]
        test = test_genHSAILRunToTwoBreakpoints(testData)
        setattr(TestWithDataFiles, test_name, test)

    unittest.main(testRunner=xmlrunner.XMLTestRunner(output="testlog"))
Beth Jelich
  • 61
  • 1
  • 3