<div dir="ltr">The biggest gains I see is that argparse takes less code, its gives a simple way to restrict the arguments passed in, and it generates help and usage with minimal user input.<div><div><div><div><br></div><div style>
2.7 shipped in 2010, and is the default on the latest OSX, most *nix distributions and has been available on windows for about a year. So bumping from 2.6 to 2.7 shouldn't be an issue.I have seen nothing that makes me think optparse will be removed from python.</div>
</div></div></div><div style><br></div><div style>-Dylan</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Mar 4, 2013 at 10:16 AM, Jordan Justen <span dir="ltr"><<a href="mailto:jljusten@gmail.com" target="_blank">jljusten@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On Sat, Mar 2, 2013 at 4:00 PM, Dylan Baker <<a href="mailto:baker.dylan.c@gmail.com">baker.dylan.c@gmail.com</a>> wrote:<br>

> This change gets us cleaner, more readable argument parsing code.<br>
> Another advantage of this approach is that it automatically generates<br>
> help menus, which means options will not be implemented without a help<br>
> entry (like --resume)<br>
><br>
> The drawback is that it makes use of argparse, which is only available<br>
> in python 2.7+ and 3.2+. However, since python 2.7 was released in<br>
> July 2010, that doesn't seem unreasonable.<br>
<br>
</div>optparse has been around since 2.3 and provides a lot of the same<br>
functionality. It is deprecated by argparse, but I don't think actual<br>
removal of optparse is planned.<br>
<br>
Does argparse provide something you need that optparse doesn't?<br>
<br>
Then again, I don't know if python 2.6 support is important.<br>
<br>
-Jordan<br>
<div><div class="h5"><br>
> Signed-off-by: Dylan Baker <<a href="mailto:baker.dylan.c@gmail.com">baker.dylan.c@gmail.com</a>><br>
> ---<br>
>  README                   |   2 +-<br>
>  piglit-print-commands.py |  80 +++++++--------------<br>
>  piglit-run.py            | 184 +++++++++++++++++++++--------------------------<br>
>  3 files changed, 109 insertions(+), 157 deletions(-)<br>
><br>
> diff --git a/README b/README<br>
> index 68108c9..69f9e9b 100644<br>
> --- a/README<br>
> +++ b/README<br>
> @@ -29,7 +29,7 @@ The original tests have been taken from<br>
><br>
>  First of all, you need to make sure that the following are installed:<br>
><br>
> -  - Python 2.6 or greater<br>
> +  - Python 2.7 or greater<br>
>    - numpy (<a href="http://www.numpy.org" target="_blank">http://www.numpy.org</a>)<br>
>    - cmake (<a href="http://www.cmake.org" target="_blank">http://www.cmake.org</a>)<br>
>    - GL, glu and glut libraries and development packages (i.e. headers)<br>
> diff --git a/piglit-print-commands.py b/piglit-print-commands.py<br>
> index 26177c5..d4a2a52 100755<br>
> --- a/piglit-print-commands.py<br>
> +++ b/piglit-print-commands.py<br>
> @@ -22,7 +22,7 @@<br>
>  # DEALINGS IN THE SOFTWARE.<br>
><br>
><br>
> -from getopt import getopt, GetoptError<br>
> +import argparse<br>
>  import os.path as path<br>
>  import re<br>
>  import sys, os<br>
> @@ -38,69 +38,39 @@ from framework.gleantest import GleanTest<br>
>  #############################################################################<br>
>  ##### Main program<br>
>  #############################################################################<br>
> -def usage():<br>
> -       USAGE = """\<br>
> -Usage: %(progName)s [options] [profile.tests]<br>
> -<br>
> -Prints a list of all the tests and how to run them.  Ex:<br>
> -   piglit test name ::: /path/to/piglit/bin/program <args><br>
> -   glean test name ::: PIGLIT_TEST='...' /path/to/piglit/bin/glean -v -v -v ...<br>
> -<br>
> -Options:<br>
> -  -h, --help                Show this message<br>
> -  -t regexp, --include-tests=regexp Run only matching tests (can be used more<br>
> -                            than once)<br>
> -  -x regexp, --exclude-tests=regexp Exclude matching tests (can be used<br>
> -                            more than once)<br>
> -Example:<br>
> -  %(progName)s tests/all.tests<br>
> -  %(progName)s -t basic tests/all.tests<br>
> -         Print tests whose path contains the word 'basic'<br>
> -<br>
> -  %(progName)s -t ^glean/ -t tex tests/all.tests<br>
> -         Print tests that are in the 'glean' group or whose path contains<br>
> -         the substring 'tex'<br>
> -"""<br>
> -       print USAGE % {'progName': sys.argv[0]}<br>
> -       sys.exit(1)<br>
><br>
>  def main():<br>
> -       env = core.Environment()<br>
> +       parser = argparse.ArgumentParser(sys.argv)<br>
> +<br>
> +       parser.add_argument("-t", "--include-tests",<br>
> +                       default = [],<br>
> +                       action  = "append",<br>
> +                       metavar = "<regex>",<br>
> +                       help    = "Run only matching tests (can be used more than once)")<br>
> +       parser.add_argument("-x", "--exclude-tests",<br>
> +                       default = [],<br>
> +                       action  = "append",<br>
> +                       metavar = "<regex>",<br>
> +                       help    = "Exclude matching tests (can be used more than once)")<br>
> +       parser.add_argument("testProfile",<br>
> +                       metavar = "<Path to testfile>",<br>
> +                       help    = "Path to results folder")<br>
> +<br>
> +       args = parser.parse_args()<br>
><br>
> -       try:<br>
> -               option_list = [<br>
> -                        "help",<br>
> -                        "include-tests=",<br>
> -                        "exclude-tests=",<br>
> -                        ]<br>
> -               options, args = getopt(sys.argv[1:], "ht:x:", option_list)<br>
> -       except GetoptError:<br>
> -               usage()<br>
> -<br>
> -       OptionName = ''<br>
> -       test_filter = []<br>
> -       exclude_filter = []<br>
> -<br>
> -       for name, value in options:<br>
> -               if name in ('-h', '--help'):<br>
> -                       usage()<br>
> -               elif name in ('-t', '--include-tests'):<br>
> -                       test_filter.append(value)<br>
> -                       env.filter.append(re.compile(value))<br>
> -               elif name in ('-x', '--exclude-tests'):<br>
> -                       exclude_filter.append(value)<br>
> -                       env.exclude_filter.append(re.compile(value))<br>
> -<br>
> -       if len(args) != 1:<br>
> -               usage()<br>
> +       env = core.Environment()<br>
><br>
> -       profileFilename = args[0]<br>
> +       # Append includes and excludes to env<br>
> +       for each in args.include_tests:<br>
> +               env.filter.append(re.compile(each))<br>
> +       for each in args.exclude_tests:<br>
> +               env.exclude_filter.append(re.compile(each))<br>
><br>
>         # Change to the piglit's path<br>
>         piglit_dir = path.dirname(path.realpath(sys.argv[0]))<br>
>         os.chdir(piglit_dir)<br>
><br>
> -       profile = core.loadTestProfile(profileFilename)<br>
> +       profile = core.loadTestProfile(args.testFile)<br>
><br>
>         def getCommand(test):<br>
>                 command = ''<br>
> diff --git a/piglit-run.py b/piglit-run.py<br>
> index a5f6ed9..57997c5 100755<br>
> --- a/piglit-run.py<br>
> +++ b/piglit-run.py<br>
> @@ -22,7 +22,7 @@<br>
>  # DEALINGS IN THE SOFTWARE.<br>
><br>
><br>
> -from getopt import getopt, GetoptError<br>
> +import argparse<br>
>  import os.path as path<br>
>  import re<br>
>  import sys, os<br>
> @@ -37,99 +37,75 @@ from framework.threads import synchronized_self<br>
>  #############################################################################<br>
>  ##### Main program<br>
>  #############################################################################<br>
> -def usage():<br>
> -       USAGE = """\<br>
> -Usage: %(progName)s [options] [profile.tests] [results]<br>
> -       %(progName)s [options] -r [results]<br>
> -<br>
> -Options:<br>
> -  -h, --help                Show this message<br>
> -  -d, --dry-run             Do not execute the tests<br>
> -  -t regexp, --include-tests=regexp Run only matching tests (can be used more<br>
> -                            than once)<br>
> -  -x regexp, --exclude-tests=regexp Excludey matching tests (can be used<br>
> -                            more than once)<br>
> -  -n name, --name=name      Name of the testrun<br>
> -  --no-concurrency          Disables concurrent test runs<br>
> -  --valgrind                Run tests in valgrind's memcheck.<br>
> -  -p platform, --platform=platform  Name of the piglit platform to use.<br>
> -  --resume                  Resume and interupted test run<br>
> -<br>
> -Example:<br>
> -  %(progName)s tests/all.tests results/all<br>
> -         Run all tests, store the results in the directory results/all<br>
> -<br>
> -  %(progName)s -t basic tests/all.tests results/all<br>
> -         Run all tests whose path contains the word 'basic'<br>
> -<br>
> -  %(progName)s -t ^glean/ -t tex tests/all.tests results/all<br>
> -         Run all tests that are in the 'glean' group or whose path contains<br>
> -                the substring 'tex'<br>
> -<br>
> -  %(progName)s -r -x bad-test results/all<br>
> -         Resume an interrupted test run whose results are stored in the<br>
> -         directory results/all, skipping bad-test.<br>
> -"""<br>
> -       print USAGE % {'progName': sys.argv[0]}<br>
> -       sys.exit(1)<br>
><br>
>  def main():<br>
>         env = core.Environment()<br>
><br>
> -       try:<br>
> -               option_list = [<br>
> -                        "help",<br>
> -                        "dry-run",<br>
> -                        "resume",<br>
> -                        "valgrind",<br>
> -                        "include-tests=",<br>
> -                        "name=",<br>
> -                        "exclude-tests=",<br>
> -                        "no-concurrency",<br>
> -                        "platform=",<br>
> -                        ]<br>
> -               options, args = getopt(sys.argv[1:], "hdrt:n:x:c:p:", option_list)<br>
> -       except GetoptError:<br>
> -               usage()<br>
> -<br>
> -       OptionName = ''<br>
> -       OptionResume = False<br>
> -       test_filter = []<br>
> -       exclude_filter = []<br>
> -       platform = None<br>
> -<br>
> -       for name, value in options:<br>
> -               if name in ('-h', '--help'):<br>
> -                       usage()<br>
> -               elif name in ('-d', '--dry-run'):<br>
> -                       env.execute = False<br>
> -               elif name in ('-r', '--resume'):<br>
> -                       OptionResume = True<br>
> -               elif name in ('--valgrind'):<br>
> -                       env.valgrind = True<br>
> -               elif name in ('-t', '--include-tests'):<br>
> -                       test_filter.append(value)<br>
> -                       env.filter.append(re.compile(value))<br>
> -               elif name in ('-x', '--exclude-tests'):<br>
> -                       exclude_filter.append(value)<br>
> -                       env.exclude_filter.append(re.compile(value))<br>
> -               elif name in ('-n', '--name'):<br>
> -                       OptionName = value<br>
> -               elif name in ('--no-concurrency'):<br>
> -                       env.concurrent = False<br>
> -               elif name in ('-p, --platform'):<br>
> -                       platform = value<br>
> -<br>
> -       if platform is not None:<br>
> -               os.environ['PIGLIT_PLATFORM'] = platform<br>
> -<br>
> -       if OptionResume:<br>
> -               if test_filter or OptionName:<br>
> -                       print "-r is not compatible with -t or -n."<br>
> -                       usage()<br>
> -               if len(args) != 1:<br>
> -                       usage()<br>
> -               resultsDir = path.realpath(args[0])<br>
> +       parser = argparse.ArgumentParser(sys.argv)<br>
> +<br>
> +<br>
> +       # Either require that a name for the test is passed or that<br>
> +       # resume is requested<br>
> +       excGroup1 = parser.add_mutually_exclusive_group()<br>
> +       excGroup1.add_argument("-n", "--name",<br>
> +                       metavar = "<test name>",<br>
> +                       default = None,<br>
> +                       help    = "Name of this test run")<br>
> +       excGroup1.add_argument("-r", "--resume",<br>
> +                       action  = "store_true",<br>
> +                       help    = "Resume an interupted test run")<br>
> +<br>
> +       parser.add_argument("-d", "--dry-run",<br>
> +                       action  = "store_true",<br>
> +                       help    = "Do not execute the tests")<br>
> +       parser.add_argument("-t", "--include-tests",<br>
> +                       default = [],<br>
> +                       action  = "append",<br>
> +                       metavar = "<regex>",<br>
> +                       help    = "Run only matching tests (can be used more than once)")<br>
> +       parser.add_argument("-x", "--exclude-tests",<br>
> +                       default = [],<br>
> +                       action  = "append",<br>
> +                       metavar = "<regex>",<br>
> +                       help    = "Exclude matching tests (can be used more than once)")<br>
> +       parser.add_argument("--no-concurrency",<br>
> +                       action  = "store_true",<br>
> +                       help    = "Disable concurrent test runs")<br>
> +       parser.add_argument("-p", "--platform",<br>
> +                       choices = ["glx", "x11_egl", "wayland", "gbm"],<br>
> +                       help    = "Name of windows system passed to waffle")<br>
> +       parser.add_argument("--valgrind",<br>
> +                       action  =  "store_true",<br>
> +                       help    = "Run tests in valgrind's memcheck")<br>
> +       parser.add_argument("testProfile",<br>
> +                       metavar = "<Path to test profile>",<br>
> +                       help    = "Path to testfile to run")<br>
> +       parser.add_argument("resultsPath",<br>
> +                       metavar = "<Results Path>",<br>
> +                       help    = "Path to results folder")<br>
> +<br>
> +       args = parser.parse_args()<br>
> +<br>
> +       # Set the platoform to pass to waffle<br>
> +       if args.platform is not None:<br>
> +               os.environ['PIGLIT_PLATFORM'] = args.platform<br>
> +<br>
> +       # Set dry-run<br>
> +       if args.dry_run is True:<br>
> +               env.execute = False<br>
> +<br>
> +       # Set valgrind<br>
> +       if args.valgrind is True:<br>
> +               env.valgrind = True<br>
> +<br>
> +       # Turn concurency off if requested<br>
> +       if args.no_concurrency is True:<br>
> +               env.concurrent = False<br>
> +<br>
> +       # If resume is requested attempt to load the results file<br>
> +       # in the specified path<br>
> +       if args.resume is True:<br>
> +               resultsDir = path.realpath(args.resultsPath)<br>
><br>
>                 # Load settings from the old results JSON<br>
>                 old_results = core.loadTestResults(resultsDir)<br>
> @@ -140,14 +116,19 @@ def main():<br>
>                 for value in old_results.options['exclude_filter']:<br>
>                         exclude_filter.append(value)<br>
>                         env.exclude_filter.append(re.compile(value))<br>
> +<br>
> +       # Otherwise parse additional settings from the command line<br>
>         else:<br>
> -               if len(args) != 2:<br>
> -                       usage()<br>
> +               profileFilename = args.testFile<br>
> +               resultsDir = args.resultsPath<br>
><br>
> -               profileFilename = args[0]<br>
> -               resultsDir = path.realpath(args[1])<br>
> +               # Set the excluded and included tests regex<br>
> +               for each in args.include_tests:<br>
> +                       env.filter.append(re.compile(each))<br>
> +               for each in args.exclude_tests:<br>
> +                       env.exclude_filter.append(re.compile(each))<br>
><br>
> -       # Change to the piglit's path<br>
> +       # Change working directory to the root of the piglit directory<br>
>         piglit_dir = path.dirname(path.realpath(sys.argv[0]))<br>
>         os.chdir(piglit_dir)<br>
><br>
> @@ -156,10 +137,10 @@ def main():<br>
>         results = core.TestrunResult()<br>
><br>
>         # Set <a href="http://results.name" target="_blank">results.name</a><br>
> -       if OptionName is '':<br>
> -               <a href="http://results.name" target="_blank">results.name</a> = path.basename(resultsDir)<br>
> +       if <a href="http://args.name" target="_blank">args.name</a> is not None:<br>
> +               <a href="http://results.name" target="_blank">results.name</a> = <a href="http://args.name" target="_blank">args.name</a><br>
>         else:<br>
> -               <a href="http://results.name" target="_blank">results.name</a> = OptionName<br>
> +               <a href="http://results.name" target="_blank">results.name</a> = path.basename(resultsDir)<br>
><br>
>         # Begin json.<br>
>         result_filepath = os.path.join(resultsDir, 'main')<br>
> @@ -172,9 +153,9 @@ def main():<br>
>         json_writer.open_dict()<br>
>         json_writer.write_dict_item('profile', profileFilename)<br>
>         json_writer.write_dict_key('filter')<br>
> -       result_file.write(json.dumps(test_filter))<br>
> +       result_file.write(json.dumps(args.include_tests))<br>
>         json_writer.write_dict_key('exclude_filter')<br>
> -       result_file.write(json.dumps(exclude_filter))<br>
> +       result_file.write(json.dumps(args.exclude_tests))<br>
>         json_writer.close_dict()<br>
><br>
>         json_writer.write_dict_item('name', <a href="http://results.name" target="_blank">results.name</a>)<br>
> @@ -188,7 +169,7 @@ def main():<br>
>         # If resuming an interrupted test run, re-write all of the existing<br>
>         # results since we clobbered the results file.  Also, exclude them<br>
>         # from being run again.<br>
> -       if OptionResume:<br>
> +       if args.resume is not None:<br>
>                 for (key, value) in old_results.tests.items():<br>
>                         if os.path.sep != '/':<br>
>                                 key = key.replace(os.path.sep, '/', -1)<br>
> @@ -212,5 +193,6 @@ def main():<br>
>         print 'Thank you for running Piglit!'<br>
>         print 'Results have been written to ' + result_filepath<br>
><br>
> +<br>
>  if __name__ == "__main__":<br>
>         main()<br>
> --<br>
> 1.8.1.2<br>
><br>
</div></div>> _______________________________________________<br>
> Piglit mailing list<br>
> <a href="mailto:Piglit@lists.freedesktop.org">Piglit@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/piglit" target="_blank">http://lists.freedesktop.org/mailman/listinfo/piglit</a><br>
</blockquote></div><br></div>