[Piglit] [PATCH 5/6] Replaces getopt with argparse

Dylan Baker baker.dylan.c at gmail.com
Sat Mar 2 16:00:55 PST 2013


This change gets us cleaner, more readable argument parsing code.
Another advantage of this approach is that it automatically generates
help menus, which means options will not be implemented without a help
entry (like --resume)

The drawback is that it makes use of argparse, which is only available
in python 2.7+ and 3.2+. However, since python 2.7 was released in
July 2010, that doesn't seem unreasonable.

Signed-off-by: Dylan Baker <baker.dylan.c at gmail.com>
---
 README                   |   2 +-
 piglit-print-commands.py |  80 +++++++--------------
 piglit-run.py            | 184 +++++++++++++++++++++--------------------------
 3 files changed, 109 insertions(+), 157 deletions(-)

diff --git a/README b/README
index 68108c9..69f9e9b 100644
--- a/README
+++ b/README
@@ -29,7 +29,7 @@ The original tests have been taken from
 
 First of all, you need to make sure that the following are installed:
 
-  - Python 2.6 or greater
+  - Python 2.7 or greater
   - numpy (http://www.numpy.org)
   - cmake (http://www.cmake.org)
   - GL, glu and glut libraries and development packages (i.e. headers)
diff --git a/piglit-print-commands.py b/piglit-print-commands.py
index 26177c5..d4a2a52 100755
--- a/piglit-print-commands.py
+++ b/piglit-print-commands.py
@@ -22,7 +22,7 @@
 # DEALINGS IN THE SOFTWARE.
 
 
-from getopt import getopt, GetoptError
+import argparse
 import os.path as path
 import re
 import sys, os
@@ -38,69 +38,39 @@ from framework.gleantest import GleanTest
 #############################################################################
 ##### Main program
 #############################################################################
-def usage():
-	USAGE = """\
-Usage: %(progName)s [options] [profile.tests]
-
-Prints a list of all the tests and how to run them.  Ex:
-   piglit test name ::: /path/to/piglit/bin/program <args>
-   glean test name ::: PIGLIT_TEST='...' /path/to/piglit/bin/glean -v -v -v ...
-
-Options:
-  -h, --help                Show this message
-  -t regexp, --include-tests=regexp Run only matching tests (can be used more
-                            than once)
-  -x regexp, --exclude-tests=regexp Exclude matching tests (can be used
-                            more than once)
-Example:
-  %(progName)s tests/all.tests
-  %(progName)s -t basic tests/all.tests
-         Print tests whose path contains the word 'basic'
-
-  %(progName)s -t ^glean/ -t tex tests/all.tests
-         Print tests that are in the 'glean' group or whose path contains
-         the substring 'tex'
-"""
-	print USAGE % {'progName': sys.argv[0]}
-	sys.exit(1)
 
 def main():
-	env = core.Environment()
+	parser = argparse.ArgumentParser(sys.argv)
+
+	parser.add_argument("-t", "--include-tests",
+			default = [],
+			action  = "append",
+			metavar = "<regex>",
+			help    = "Run only matching tests (can be used more than once)")
+	parser.add_argument("-x", "--exclude-tests",
+			default = [],
+			action  = "append",
+			metavar = "<regex>",
+			help    = "Exclude matching tests (can be used more than once)")
+	parser.add_argument("testProfile",
+			metavar = "<Path to testfile>",
+			help    = "Path to results folder")
+
+	args = parser.parse_args()
 
-	try:
-		option_list = [
-			 "help",
-			 "include-tests=",
-			 "exclude-tests=",
-			 ]
-		options, args = getopt(sys.argv[1:], "ht:x:", option_list)
-	except GetoptError:
-		usage()
-
-	OptionName = ''
-	test_filter = []
-	exclude_filter = []
-
-	for name, value in options:
-		if name in ('-h', '--help'):
-			usage()
-		elif name in ('-t', '--include-tests'):
-			test_filter.append(value)
-			env.filter.append(re.compile(value))
-		elif name in ('-x', '--exclude-tests'):
-			exclude_filter.append(value)
-			env.exclude_filter.append(re.compile(value))
-
-	if len(args) != 1:
-		usage()
+	env = core.Environment()
 
-	profileFilename = args[0]
+	# Append includes and excludes to env
+	for each in args.include_tests:
+		env.filter.append(re.compile(each))
+	for each in args.exclude_tests:
+		env.exclude_filter.append(re.compile(each))
 
 	# Change to the piglit's path
 	piglit_dir = path.dirname(path.realpath(sys.argv[0]))
 	os.chdir(piglit_dir)
 
-	profile = core.loadTestProfile(profileFilename)
+	profile = core.loadTestProfile(args.testFile)
 
 	def getCommand(test):
 		command = ''
diff --git a/piglit-run.py b/piglit-run.py
index a5f6ed9..57997c5 100755
--- a/piglit-run.py
+++ b/piglit-run.py
@@ -22,7 +22,7 @@
 # DEALINGS IN THE SOFTWARE.
 
 
-from getopt import getopt, GetoptError
+import argparse
 import os.path as path
 import re
 import sys, os
@@ -37,99 +37,75 @@ from framework.threads import synchronized_self
 #############################################################################
 ##### Main program
 #############################################################################
-def usage():
-	USAGE = """\
-Usage: %(progName)s [options] [profile.tests] [results]
-       %(progName)s [options] -r [results]
-
-Options:
-  -h, --help                Show this message
-  -d, --dry-run             Do not execute the tests
-  -t regexp, --include-tests=regexp Run only matching tests (can be used more
-                            than once)
-  -x regexp, --exclude-tests=regexp Excludey matching tests (can be used
-                            more than once)
-  -n name, --name=name      Name of the testrun
-  --no-concurrency          Disables concurrent test runs
-  --valgrind                Run tests in valgrind's memcheck.
-  -p platform, --platform=platform  Name of the piglit platform to use.
-  --resume                  Resume and interupted test run
-
-Example:
-  %(progName)s tests/all.tests results/all
-         Run all tests, store the results in the directory results/all
-
-  %(progName)s -t basic tests/all.tests results/all
-         Run all tests whose path contains the word 'basic'
-
-  %(progName)s -t ^glean/ -t tex tests/all.tests results/all
-         Run all tests that are in the 'glean' group or whose path contains
-		 the substring 'tex'
-
-  %(progName)s -r -x bad-test results/all
-         Resume an interrupted test run whose results are stored in the
-         directory results/all, skipping bad-test.
-"""
-	print USAGE % {'progName': sys.argv[0]}
-	sys.exit(1)
 
 def main():
 	env = core.Environment()
 
-	try:
-		option_list = [
-			 "help",
-			 "dry-run",
-			 "resume",
-			 "valgrind",
-			 "include-tests=",
-			 "name=",
-			 "exclude-tests=",
-			 "no-concurrency",
-			 "platform=",
-			 ]
-		options, args = getopt(sys.argv[1:], "hdrt:n:x:c:p:", option_list)
-	except GetoptError:
-		usage()
-
-	OptionName = ''
-	OptionResume = False
-	test_filter = []
-	exclude_filter = []
-	platform = None
-
-	for name, value in options:
-		if name in ('-h', '--help'):
-			usage()
-		elif name in ('-d', '--dry-run'):
-			env.execute = False
-		elif name in ('-r', '--resume'):
-			OptionResume = True
-		elif name in ('--valgrind'):
-			env.valgrind = True
-		elif name in ('-t', '--include-tests'):
-			test_filter.append(value)
-			env.filter.append(re.compile(value))
-		elif name in ('-x', '--exclude-tests'):
-			exclude_filter.append(value)
-			env.exclude_filter.append(re.compile(value))
-		elif name in ('-n', '--name'):
-			OptionName = value
-		elif name in ('--no-concurrency'):
-			env.concurrent = False
-		elif name in ('-p, --platform'):
-			platform = value
-
-	if platform is not None:
-		os.environ['PIGLIT_PLATFORM'] = platform
-
-	if OptionResume:
-		if test_filter or OptionName:
-			print "-r is not compatible with -t or -n."
-			usage()
-		if len(args) != 1:
-			usage()
-		resultsDir = path.realpath(args[0])
+	parser = argparse.ArgumentParser(sys.argv)
+
+
+	# Either require that a name for the test is passed or that
+	# resume is requested
+	excGroup1 = parser.add_mutually_exclusive_group()
+	excGroup1.add_argument("-n", "--name",
+			metavar = "<test name>",
+			default = None,
+			help    = "Name of this test run")
+	excGroup1.add_argument("-r", "--resume",
+			action  = "store_true",
+			help    = "Resume an interupted test run")
+
+	parser.add_argument("-d", "--dry-run",
+			action  = "store_true",
+			help    = "Do not execute the tests")
+	parser.add_argument("-t", "--include-tests",
+			default = [],
+			action  = "append",
+			metavar = "<regex>",
+			help    = "Run only matching tests (can be used more than once)")
+	parser.add_argument("-x", "--exclude-tests",
+			default = [],
+			action  = "append",
+			metavar = "<regex>",
+			help    = "Exclude matching tests (can be used more than once)")
+	parser.add_argument("--no-concurrency",
+			action  = "store_true",
+			help    = "Disable concurrent test runs")
+	parser.add_argument("-p", "--platform",
+			choices = ["glx", "x11_egl", "wayland", "gbm"],
+			help    = "Name of windows system passed to waffle")
+	parser.add_argument("--valgrind",
+			action  =  "store_true",
+			help    = "Run tests in valgrind's memcheck")
+	parser.add_argument("testProfile",
+			metavar = "<Path to test profile>",
+			help    = "Path to testfile to run")
+	parser.add_argument("resultsPath",
+			metavar = "<Results Path>",
+			help    = "Path to results folder")
+
+	args = parser.parse_args()
+
+	# Set the platoform to pass to waffle
+	if args.platform is not None:
+		os.environ['PIGLIT_PLATFORM'] = args.platform
+
+	# Set dry-run
+	if args.dry_run is True:
+		env.execute = False
+
+	# Set valgrind
+	if args.valgrind is True:
+		env.valgrind = True
+
+	# Turn concurency off if requested
+	if args.no_concurrency is True:
+		env.concurrent = False
+
+	# If resume is requested attempt to load the results file
+	# in the specified path
+	if args.resume is True:
+		resultsDir = path.realpath(args.resultsPath)
 
 		# Load settings from the old results JSON
 		old_results = core.loadTestResults(resultsDir)
@@ -140,14 +116,19 @@ def main():
 		for value in old_results.options['exclude_filter']:
 			exclude_filter.append(value)
 			env.exclude_filter.append(re.compile(value))
+
+	# Otherwise parse additional settings from the command line
 	else:
-		if len(args) != 2:
-			usage()
+		profileFilename = args.testFile
+		resultsDir = args.resultsPath
 
-		profileFilename = args[0]
-		resultsDir = path.realpath(args[1])
+		# Set the excluded and included tests regex
+		for each in args.include_tests:
+			env.filter.append(re.compile(each))
+		for each in args.exclude_tests:
+			env.exclude_filter.append(re.compile(each))
 
-	# Change to the piglit's path
+	# Change working directory to the root of the piglit directory
 	piglit_dir = path.dirname(path.realpath(sys.argv[0]))
 	os.chdir(piglit_dir)
 
@@ -156,10 +137,10 @@ def main():
 	results = core.TestrunResult()
 
 	# Set results.name
-	if OptionName is '':
-		results.name = path.basename(resultsDir)
+	if args.name is not None:
+		results.name = args.name
 	else:
-		results.name = OptionName
+		results.name = path.basename(resultsDir)
 
 	# Begin json.
 	result_filepath = os.path.join(resultsDir, 'main')
@@ -172,9 +153,9 @@ def main():
 	json_writer.open_dict()
 	json_writer.write_dict_item('profile', profileFilename)
 	json_writer.write_dict_key('filter')
-	result_file.write(json.dumps(test_filter))
+	result_file.write(json.dumps(args.include_tests))
 	json_writer.write_dict_key('exclude_filter')
-	result_file.write(json.dumps(exclude_filter))
+	result_file.write(json.dumps(args.exclude_tests))
 	json_writer.close_dict()
 
 	json_writer.write_dict_item('name', results.name)
@@ -188,7 +169,7 @@ def main():
 	# If resuming an interrupted test run, re-write all of the existing
 	# results since we clobbered the results file.  Also, exclude them
 	# from being run again.
-	if OptionResume:
+	if args.resume is not None:
 		for (key, value) in old_results.tests.items():
 			if os.path.sep != '/':
 				key = key.replace(os.path.sep, '/', -1)
@@ -212,5 +193,6 @@ def main():
 	print 'Thank you for running Piglit!'
 	print 'Results have been written to ' + result_filepath
 
+
 if __name__ == "__main__":
 	main()
-- 
1.8.1.2



More information about the Piglit mailing list