changeset 193:a76cdc26ba9d

Added conf. var. match and match='regexp' for non-archives Specify match='regexp', and your tests and dummies will be treated as regular expressions describing test case identifiers. Every file that is in a suitable location and whose name matches {testcase,dummy}inname and the given regexp will be treated as a file with test case input data. You are free to use backreferences in the regexps, but group numbering starts at two rather than one. If you want test groups, you can get them magically created for you by putting a part of the test ID in a group in the regexp sense and specifying the tests variable as a pair consisting of the regexp itself and the number of this regexp group (remember group numbers start at two).
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 11 Aug 2011 23:20:52 +0300
parents 6e6b0ea63fa1
children 8c30a2c8a09e
files upreckon/config.py upreckon/files.py upreckon/problem.py
diffstat 3 files changed, 63 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/upreckon/config.py	Thu Aug 11 20:44:23 2011 +0300
+++ b/upreckon/config.py	Thu Aug 11 23:20:52 2011 +0300
@@ -23,6 +23,7 @@
                     'maxcputime': None,
                     'maxwalltime': None,
                     'maxmemory': None,
+                    'match': '$%',
                     'dummies': (),
                     'testsexcluded': (),
                     'padtests': 0,
--- a/upreckon/files.py	Thu Aug 11 20:44:23 2011 +0300
+++ b/upreckon/files.py	Thu Aug 11 23:20:52 2011 +0300
@@ -5,10 +5,10 @@
 from __future__ import division, with_statement
 
 from .compat import *
-import contextlib, os, posixpath, shutil, sys
+import contextlib, itertools, os, posixpath, re, shutil, sys
 
 # You don't need to know about anything else.
-__all__ = 'File',
+__all__ = 'File', 'regexp'
 
 # In these two variables, use full stops no matter what os.extsep is;
 # all full stops will be converted to os.extsep on the fly
@@ -239,4 +239,26 @@
 		if self.archive:
 			self.archive.extract(self.real_path, target)
 		else:
-			shutil.copy(self.real_path, target)
\ No newline at end of file
+			shutil.copy(self.real_path, target)
+
+def regexp(pattern, hastests=False, droplast=False):
+	# FIXME: add test archives
+	if not pattern:
+		yield os.curdir, ''
+		return
+	dirname, basename = posixpath.split(pattern)
+	if hastests:
+		dirnames = regexp(dirname, True)
+	else:
+		dirnames = itertools.chain(regexp(dirname), regexp(posixpath.join(dirname, 'tests'), True, True))
+	reobj = re.compile(pattern + '$', re.UNICODE)
+	for dirname, vdirname in dirnames:
+		try:
+			names = os.listdir(dirname)
+		except OSError:
+			continue
+		for name in names:
+			path = os.path.join(dirname, name)
+			vpath = posixpath.join(vdirname, name)
+			if re.match(reobj, vpath):
+				yield path, vpath if not droplast else vdirname
--- a/upreckon/problem.py	Thu Aug 11 20:44:23 2011 +0300
+++ b/upreckon/problem.py	Thu Aug 11 23:20:52 2011 +0300
@@ -4,7 +4,7 @@
 
 from .compat import *
 from .exceptions import *
-from . import config, testcases
+from . import config, files, testcases
 from __main__ import options
 
 import os, re, sys
@@ -248,6 +248,21 @@
 	except Exception:
 		prob.config.tests = tuple(prob.config.tests)
 	
+	if prob.config.match == 're':
+		if not prob.config.usegroups:
+			prob.config.tests = prob.config.tests, None
+		elif isinstance(prob.config.tests, basestring):
+			prob.config.tests = prob.config.tests, 2
+		parts = tuple(map(re.escape, prob.config.dummyinname.split('$')))
+		probname = re.escape(prob.name) + '/' if prob.name != os.curdir else ''
+		path = '%s%s(%s)' % (probname, parts[0], prob.config.dummies)
+		path += r'\1'.join(parts[1:])
+		prob.config.dummies = regexp(path, None)
+		parts = tuple(map(re.escape, prob.config.testcaseinname.split('$')))
+		path = '%s%s(%s)' % (probname, parts[0], prob.config.tests[0])
+		path += r'\1'.join(parts[1:])
+		prob.config.tests = regexp(path, prob.config.tests[1])
+	
 	if options.legacy:
 		prob.config.usegroups = False
 		newtests = []
@@ -335,3 +350,24 @@
 			s = str(i).zfill(prob.config.padtests)
 			if (yield _types[prob.config.kind](prob, s, False, getpoints(i, j))):
 				yield
+
+def regexp(pattern, group):
+	reobj = re.compile(pattern, re.UNICODE)
+	if not group:
+		ids = []
+		for path, vpath in files.regexp(pattern):
+			ids.append(re.match(reobj, vpath).group(1))
+		return natsorted(ids)
+	else:
+		ids = {}
+		for path, vpath in files.regexp(pattern):
+			m = re.match(reobj, vpath)
+			g = m.group(group)
+			ids.setdefault(g, [])
+			ids[g].append(m.group(1))
+		for g in ids:
+			ids[g] = natsorted(ids[g])
+		return [ids[g] for g in natsorted(keys(ids))]
+
+def natsorted(l):
+	return sorted(l, key=lambda s: [int(t) if t.isdigit() else t for t in re.split('(\d+)', s)])