classification
Title: Add ability to inherit unittest arguement parser
Type: behavior Stage:
Components: Library (Lib) Versions:
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: atb00ker, paul.j3, xtreak
Priority: normal Keywords:

Created on 2020-01-10 04:32 by atb00ker, last changed 2020-01-18 01:46 by paul.j3.

Messages (4)
msg359704 - (view) Author: Ajay Tripathi (atb00ker) Date: 2020-01-10 04:32
I am currently writing a unittest script that requires argparser but since the unittest module already has a ArgumentParser instance, I cannot create and use my own ArgumentParser instance.


Possible solution:

The problem would be solved I could inherit the parent ArgumentParser instance created here:
https://github.com/python/cpython/blob/master/Lib/unittest/main.py#L162

Please let me know if it's feasible / acceptable to change `parent_parser` as `self.parent_parent` for inheritance.

I would love to create a pull request for it.
msg359716 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2020-01-10 09:47
Can you please post the unittest script and the desired behavior? Are you testing your own argument parser created using argparse or want to write something replacing the argument parser of the unittest module like creating a custom unittest runner?
msg359949 - (view) Author: Ajay Tripathi (atb00ker) Date: 2020-01-14 07:01
Hi,

Thanks for your response, here is a code sample of what I am doing right now:

```
import unittest
import sys

class MyTest(unittest.TestCase):

    def __init__(self, testName, extraArg):
        super(MyTest, self).__init__(testName)
        self.myExtraArg = extraArg

    def test_something(self):
        print(self.myExtraArg)

extraArg = sys.argv.pop()
suite = unittest.TestSuite()
suite.addTest(MyTest('test_something', extraArg))
unittest.TextTestRunner(verbosity=2).run(suite)
```

It works.
However, this can be cumbersome if there are a lot of "extraArgs" and MyTestClasses.
Especically, if there is an existing argparser function existing that is used in the program, re-writing the code for passing args in another way for unittest doesn't seem ideal.


Ideally, I think something like this may work perfectly:

```
import unittest


class SomethingLikeInheritedUnitest(unittest.TestProgram):
    # parent_parser is used here: https://github.com/python/cpython/blob/master/Lib/unittest/main.py#L162
    parent = super().createParentArgParserAndReturnIt()
    parser = argparse.ArgumentParser(parents=[parent])
    parser.add_argument('--myarg1', ...)
    parser.add_argument('--myarg2', ...)
    return parser
```

Now the parser may be exposed to user's MyTest class and they can use
arguements as: `paser.myarg1`


Note: I am not certain this may be the way to go about it, there may be a better way, infact, I've not even had the time to read the entire code. :-( 
I am only trying to point out is that the ability to add `myarg1` in the parent_parser may be useful at times.

Hope this makes the point a bit more clear. If I have misunderstood something please correct me.



Thank You,
Ajay Tripathi
msg360226 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2020-01-18 01:46
The issue of testing a script that uses argparse has come up on StackOverFlow a number of times.  

As noted the unittesting framework(s) often use their own parsers (not necessarily argparse).  That means they are looking at the sys.argv commandline.  It is difficult then to provide arguments that apply both to the framework, and your own script.  If you try to your own options, the unittest parser will complain about unrecognized arguments.

As a first step, your parser should only run when used as a script, not when imported (by the unittester).  In other words, only call `parse_args` in the 'if __name__' block.

If you do need to do unittesting of your parser, there are several monkey-patching options:

    use 'parser.parse_args(argv)' calls, where 'argv' can be None if used as script, and a custom list when being tested.  Some will modify the sys.argv during testing.  The test_argparse.py unittest file tests both ways.

    testing parser output may also require patching.  Help and errors are sent to sys.stdout or sys.stderr.  test_argparse.py uses an ArgumentParser subclass that redefines the error() and exit() methods, and redirects stdout/err.
History
Date User Action Args
2020-01-18 01:46:59paul.j3setnosy: + paul.j3
messages: + msg360226
2020-01-14 07:01:28atb00kersetmessages: + msg359949
2020-01-10 09:47:19xtreaksetnosy: + xtreak
messages: + msg359716
2020-01-10 04:32:18atb00kercreate