Mercurial > ~astiob > upreckon > hgweb
view upreckon/config.py @ 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 | 35d59ba0e27c |
children | 1de2ea435d93 |
line wrap: on
line source
# Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv> from __future__ import division, with_statement from .compat import * from . import files from __main__ import options, args if files.ZipArchive: try: import zipimport except ImportError: zipimport = None else: zipimport = None import imp, os, posixpath, sys, tempfile __all__ = 'load_problem', 'load_global', 'globalconf', 'nativize_path' defaults_problem = {'kind': 'batch', 'usegroups': False, 'maxcputime': None, 'maxwalltime': None, 'maxmemory': None, 'match': '$%', 'dummies': (), 'testsexcluded': (), 'padtests': 0, 'paddummies': 0, 'taskweight': 100, 'groupweight': {}, 'pointmap': {}, 'stdio': False, 'binary': False, 'dummyinname': '', 'dummyoutname': '', 'tester': None, 'maxexitcode': 0, 'inname': '', 'ansname': ''} defaults_global = {'problems': None, 'force_zero_exitcode': True} defaults_noerase = {'inname': '%.in', 'outname': '%.out', 'ansname': '%.ans'} patterns = ('inname', 'outname', 'ansname', 'testcaseinname', 'testcaseoutname', 'dummyinname', 'dummyoutname') class Config(object): __slots__ = 'modules', '__dict__' def __init__(self, *modules): self.modules = modules def __getattr__(self, name): for module in self.modules: try: return getattr(module, name) except AttributeError: pass # TODO: provide a message raise AttributeError(name) # A helper context manager class ReadDeleting(object): __slots__ = 'name', 'file' def __init__(self, name): self.name = name def __enter__(self): try: self.file = open(self.name, 'rU') return self.file except: try: self.__exit__(None, None, None) except: pass raise def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() os.remove(self.name) def nativize_path(portable_path): if portable_path.startswith('//:'): return portable_path[3:] comps = portable_path.split('/') for i, comp in enumerate(comps): if comp == '..': comps[i] = os.path.pardir elif comp == '.': comps[i] = os.path.curdir native_path = os.path.join(*comps) if posixpath.isabs(portable_path) and not os.path.isabs(native_path): abspath = os.path.abspath(native_path) parent = os.path.dirname(abspath) while parent != abspath: abspath, parent = parent, os.path.dirname(parent) native_path = os.path.join(parent, native_path) elif not posixpath.isabs(portable_path) and os.path.isabs(native_path): native_path = os.path.sep + native_path if posixpath.isabs(portable_path) != os.path.isabs(native_path): raise ValueError('cannot make native path relative/absolute') return native_path def load_problem(problem_name): global builtins try: dwb = sys.dont_write_bytecode sys.dont_write_bytecode = True except AttributeError: pass metafile = files.File(problem_name + '/testconf.py', True, 'configuration') module = None with CompatBuiltins() as builtins: if zipimport and isinstance(metafile.archive, files.ZipArchive): try: module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf') except zipimport.ZipImportError: pass else: del sys.modules['testconf'] if not module: try: with metafile.open() as f: module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) # Handle the case when f is not a true file object but imp requires one except ValueError: # FIXME: 2.5 lacks the delete parameter with tempfile.NamedTemporaryFile(delete=False) as f: inputdatafname = f.name metafile.copy(inputdatafname) with ReadDeleting(inputdatafname) as f: module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) del sys.modules['testconf'] module = Config(module, globalconf) if hasattr(module, 'padwithzeroestolength'): if not hasattr(module, 'padtests'): try: module.padtests = module.padwithzeroestolength[0] except TypeError: module.padtests = module.padwithzeroestolength if not hasattr(module, 'paddummies'): try: module.paddummies = module.padwithzeroestolength[1] except TypeError: module.paddummies = module.padwithzeroestolength if (not hasattr(module, 'maxcputime') and not hasattr(module, 'maxwalltime') and hasattr(module, 'maxtime')): module.maxcputime = module.maxtime for name in defaults_problem: setattr(module, name, getattr(module, name, defaults_problem[name])) if not module.dummyinname: module.dummyinname = getattr(module, 'testcaseinname', module.dummyinname) if not module.dummyoutname: module.dummyoutname = getattr(module, 'testcaseoutname', module.dummyoutname) if hasattr(module, 'testee'): if isinstance(module.testee, basestring): module.path = nativize_path(module.testee) else: testee = tuple(module.testee) module.path = (nativize_path(testee[0]),) + testee[1:] elif not hasattr(module, 'path'): if hasattr(module, 'name'): module.path = module.name elif sys.platform != 'win32': module.path = os.path.join(os.path.curdir, problem_name) else: module.path = problem_name if module.tester: if isinstance(module.tester, basestring): module.tester = nativize_path(module.tester) elif not callable(module.tester): tester = tuple(module.tester) module.tester = (nativize_path(tester[0]),) + tester[1:] for name in 'pointmap', 'groupweight': oldmap = getattr(module, name) if isinstance(oldmap, dict): newmap = {} for key in oldmap: if not options.legacy and isinstance(key, basestring): newmap[key] = oldmap[key] else: try: for k in key: newmap[k] = oldmap[key] except TypeError: newmap[key] = oldmap[key] setattr(module, name, newmap) if options.no_maxtime: module.maxcputime = module.maxwalltime = 0 if args: module.usegroups = False module.tests = args module.dummies = () try: sys.dont_write_bytecode = dwb except NameError: pass for name in patterns: if hasattr(module, name): setattr(module, name, getattr(module, name).replace('%', problem_name)) return module def load_global(): global builtins try: dwb = sys.dont_write_bytecode sys.dont_write_bytecode = True except AttributeError: pass metafile = files.File('testconf.py', True, 'configuration') module = None with CompatBuiltins() as builtins: if zipimport and isinstance(metafile.archive, files.ZipArchive): try: module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf') except zipimport.ZipImportError: pass else: del sys.modules['testconf'] if not module: try: with metafile.open() as f: module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) # Handle the case when f is not a true file object but imp requires one except ValueError: # FIXME: 2.5 lacks the delete parameter with tempfile.NamedTemporaryFile(delete=False) as f: inputdatafname = f.name metafile.copy(inputdatafname) with ReadDeleting(inputdatafname) as f: module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) del sys.modules['testconf'] for name in defaults_global: setattr(module, name, getattr(module, name, defaults_global[name])) if not options.erase: for name in defaults_noerase: setattr(module, name, getattr(module, name, defaults_noerase[name])) if hasattr(module, 'tasknames'): module.problems = module.tasknames global globalconf globalconf = module try: sys.dont_write_bytecode = dwb except NameError: pass return module