changeset 16:f2279b7602d3

Initial 2.00 commit
author Oleg Oshmyan <chortos@inbox.lv>
date Mon, 07 Jun 2010 23:36:52 +0000
parents c0e925ae721e
children dfe872cafbd0
files 2.00/compat.py 2.00/config.py 2.00/files.py 2.00/problem.py 2.00/test-svn.py 2.00/testcases.py
diffstat 6 files changed, 258 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/compat.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>
+
+try:
+	# Python 3
+	exec('say = print')
+except SyntaxError:
+	try:
+		# Python 2.6/2.7
+		exec('say = __builtins__["print"]')
+	except Exception:
+		# Python 2.5
+		import sys
+		# This should fully emulate the print function of Python 2.6 in Python 2.3+
+		# The error messages are taken from Python 2.6/2.7
+		def saytypeerror(value, name):
+			return TypeError(name + ' must be None, str or unicode, not ' + type(value).__name__)
+		def say(*values, **kwargs):
+			sep  = kwargs.pop('sep' , None)
+			end  = kwargs.pop('end' , None)
+			file = kwargs.pop('file', None)
+			if kwargs: raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.popitem()[0])
+			if sep  is None: sep  = ' '
+			if end  is None: end  = '\n'
+			if file is None: file = sys.stdout
+			if not isinstance(sep, basestring): raise saytypeerror(sep, 'sep')
+			if not isinstance(end, basestring): raise saytypeerror(end, 'end')
+			file.write(sep.join((str(i) for i in values)) + end)
+
+def import_urllib():
+	try:
+		# Python 3
+		import urllib.request
+		return urllib.request, lambda url: urllib.request.urlopen(url).read().decode()
+	except ImportError:
+		# Python 2
+		import urllib
+		return urllib, lambda url: urllib.urlopen(url).read()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/config.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>
+
+import os
+tasknames = (os.path.curdir,)
+
+def load_problem(name):
+	return object()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/files.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>
+
+import os
+tasknames = (os.path.curdir,)
+
+class Files(object):
+	__slots__ = 'name', 'paths'
+	stdpaths = '%/', '%/^:%/', '%/^:', 'tests/%/', 'tests/', '^:%/', '^:', ''
+	
+	def __init__(self, name, paths = stdpaths):
+		self.name = name
+		self.paths = paths
+	
+	def __iter__(self):
+		for path in paths:
+			p = getpath(path, self.name)
+			if isfile(p):
+				yield p
+
+def isfile(path):
+	return os.path.isfile(path)
+
+def getpath(path, name):
+	return path + name
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/problem.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>
+
+try:
+	import config as _config, testcases as _testcases
+except ImportError as e:
+	import __main__
+	__main__.import_error(e)
+
+# LIBRARY and STDIO refer to interactive aka reactive problems
+BATCH, OUTONLY, LIBRARY, STDIO, BESTOUT = xrange(5)
+
+class Problem(object):
+	__slots__ = 'name', 'config', 'cache', 'testcases'
+	
+	def __init__(prob, name):
+		if not isinstance(name, basestring):
+			# This shouldn't happen, of course
+			raise TypeError, "Problem() argument 1 must be string, not " + str(type(name)).split('\'')[1]
+		prob.name = name
+		prob.config = _config.load_problem(name)
+		prob.cache = type('Cache', (object,), {'padoutputtolength': 0})()
+		prob.testcases = _testcases.load_problem(prob)
+	
+	def test(prob):
+		real = max = 0
+		for case in prob.testcases:
+			r, m = case()
+			real += r
+			max += m
+		return real, max
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/test-svn.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+# Copyright (c) 2009-2010 Chortos-2 <chortos@inbox.lv>
+
+from __future__ import division, with_statement
+import optparse, sys, compat
+from compat import say
+
+# $Rev: 15 $
+version = '2.00.0 (SVN r$$REV$$)'
+parser = optparse.OptionParser(version='test.py '+version, epilog='Python 2.5 or newer is required, unless you have a custom build of Python.')
+parser.add_option('-u', '--update', dest='update', action='store_true', default=False, help='check for an updated version of test.py')
+parser.add_option('-m', '--copy-io', dest='copyonly', action='store_true', default=False, help='create a copy of the input/output files of the last test case for manual testing and exit')
+parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed after finishing testing')
+
+options, args = parser.parse_args()
+parser.destroy()
+del parser
+
+if options.update:
+	try:
+		urllib, urlread = compat.import_urllib()
+	except ImportError:
+		sys.exit('Error: the urllib Python module is missing. Without it, an automatic update is impossible.')
+	
+	latesttext = urlread('http://chortos.selfip.net/~astiob/test.py/version.txt')
+	latest = latesttext.split('.')
+	installed = version.split('.')
+	update = None
+	
+	if latest[0] > installed[0]:
+		update = 'major'
+	elif latest[0] == installed[0]:
+		if latest[1] > installed[1]:
+			update = 'feature'
+		elif latest[1] == installed[1]:
+			if latest[2] > installed[2]:
+				update = 'bug-fixing'
+			elif latest[2] == installed[2]:
+				say('You are using the latest publicly available version of test.py.')
+				sys.exit()
+	
+	if not update:
+		say('Your copy of test.py is newer than the publicly available version.')
+		sys.exit()
+	
+	say('A ' + update + ' update to test.py is available. Downloading...')
+	sys.stdout.flush()
+	urllib.urlretrieve('http://chortos.selfip.net/~astiob/test.py/test.py', sys.argv[0])
+	say('Downloaded and installed. Now you are using test.py ' + latesttext + '.')
+	sys.exit()
+
+def import_error(e):
+	say('Your installation of test.py is incomplete:', str(e).lower() + '.', file=sys.stderr)
+	sys.exit(3)
+
+import os, config
+
+# Do this check here so that if we have to warn them, we do it as early as possible
+if options.pause and not hasattr(config, 'pause'):
+	try:
+		# If we have getch, we don't need config.pause
+		import msvcrt
+		msvcrt.getch.__call__
+	except Exception:
+		if os.name == 'posix':
+			config.pause = 'read -s -n 1'
+			say('Warning: configuration variable pause is not defined; it was devised automatically but the choice might be incorrect, so test.py might exit immediately after the testing is completed.')
+			sys.stdout.flush()
+		elif os.name == 'nt':
+			config.pause = 'pause'
+		else:
+			sys.exit('Error: configuration variable pause is not defined and cannot be devised automatically.')
+
+try:
+	from problem import *
+except ImportError as e:
+	import_error(e)
+
+# Support single-problem configurations
+try:
+	shouldprintnames = len(config.tasknames) > 1
+except Exception:
+	shouldprintnames = True
+
+ntasks = 0
+nfulltasks = 0
+maxscore = 0
+realscore = 0
+
+for taskname in config.tasknames:
+	problem = Problem(taskname)
+	
+	if ntasks: say()
+	if shouldprintnames: say(taskname)
+	
+	if options.copyonly:
+		problem.copytestdata()
+	else:
+		real, max = problem.test()
+	
+	ntasks += 1
+	nfulltasks += (real == max)
+	realscore += real
+	maxscore += max
+
+if options.copyonly:
+	sys.exit()
+
+if ntasks != 1:
+	say()
+	say('Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (realscore, maxscore, nfulltasks, ntasks))
+
+if options.pause:
+	say('Press any key to exit...', end='')
+	sys.stdout.flush()
+	
+	try:
+		import msvcrt
+		msvcrt.getch()
+	except Exception:
+		os.system(config.pause + ' >' + os.devnull)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2.00/testcases.py	Mon Jun 07 23:36:52 2010 +0000
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>
+
+try:
+	import files as _files, problem as _problem
+except ImportError as e:
+	import __main__
+	__main__.import_error(e)
+
+class TestCase(object):
+	__slots__ = 'problem', 'infile', 'outfile'
+	
+	def __init__(case, prob, infile, outfile):
+		case.problem = prob
+		case.infile = infile
+		case.outfile = outfile
+	
+	def __call__(case):
+		os.copy()
+
+def load_problem(prob):
+	if prob.config.usegroups:
+		pass
+	else:
+		for i in prob.config.tests:
+			s = str(i).zfill(prob.config.padwithzeroestolength)
+			prob.cache.padoutputtolength = max(prob.cache.padoutputtolength, len(s))
+			infile = _files.TestCaseFile(prob, prob.config.testcaseinname.replace('$', s))
+			if infile:
+				if prob.config.kind != _problem.BATCH:
+					yield TestCase(prob, infile, None)
+				else:
+					outfile = _files.TestCaseFile(prob, prob.config.testcaseoutname.replace('$', s))
+					if outfile:
+						yield TestCase(prob, infile, outfile)
\ No newline at end of file