comparison upreckon/config.py @ 146:d5b6708c1955

Distutils support, reorganization and cleaning up * Removed command-line options -t and -u. * Reorganized code: o all modules are now in package upreckon; o TestCaseNotPassed and its descendants now live in a separate module exceptions; o load_problem now lives in module problem. * Commented out mentions of command-line option -c in --help. * Added a distutils-based setup.py.
author Oleg Oshmyan <chortos@inbox.lv>
date Sat, 28 May 2011 14:24:25 +0100
parents config.py@6589511f5418
children 006dce02752c
comparison
equal deleted inserted replaced
145:d2c266c8d820 146:d5b6708c1955
1 # Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv>
2
3 from __future__ import division, with_statement
4
5 from .compat import *
6 from . import files
7 from __main__ import options
8
9 if files.ZipArchive:
10 try:
11 import zipimport
12 except ImportError:
13 zipimport = None
14 else:
15 zipimport = None
16
17 import imp, os, sys, tempfile
18
19 __all__ = 'load_problem', 'load_global', 'globalconf'
20
21 defaults_problem = {'kind': 'batch',
22 'usegroups': False,
23 'maxcputime': None,
24 'maxwalltime': None,
25 'maxmemory': None,
26 'dummies': (),
27 'testsexcluded': (),
28 'padtests': 0,
29 'paddummies': 0,
30 'taskweight': 100,
31 'groupweight': {},
32 'pointmap': {},
33 'stdio': False,
34 'dummyinname': '',
35 'dummyoutname': '',
36 'tester': None,
37 'maxexitcode': 0,
38 'inname': '',
39 'ansname': ''}
40 defaults_global = {'problems': None,
41 'force_zero_exitcode': True}
42 defaults_noerase = {'inname': '%.in',
43 'outname': '%.out',
44 'ansname': '%.ans'}
45 patterns = ('inname', 'outname', 'ansname', 'testcaseinname',
46 'testcaseoutname', 'dummyinname', 'dummyoutname')
47
48 class Config(object):
49 __slots__ = 'modules', '__dict__'
50
51 def __init__(self, *modules):
52 self.modules = modules
53
54 def __getattr__(self, name):
55 for module in self.modules:
56 try:
57 return getattr(module, name)
58 except AttributeError:
59 pass
60 # TODO: provide a message
61 raise AttributeError(name)
62
63 # A helper context manager
64 class ReadDeleting(object):
65 __slots__ = 'name', 'file'
66
67 def __init__(self, name):
68 self.name = name
69
70 def __enter__(self):
71 try:
72 self.file = open(self.name, 'rU')
73 return self.file
74 except:
75 try:
76 self.__exit__(None, None, None)
77 except:
78 pass
79 raise
80
81 def __exit__(self, exc_type, exc_val, exc_tb):
82 self.file.close()
83 os.remove(self.name)
84
85 def load_problem(problem_name):
86 global builtins
87 try:
88 dwb = sys.dont_write_bytecode
89 sys.dont_write_bytecode = True
90 except AttributeError:
91 pass
92 metafile = files.File('/'.join((problem_name, 'testconf.py')), True, 'configuration')
93 module = None
94 with CompatBuiltins() as builtins:
95 if zipimport and isinstance(metafile.archive, files.ZipArchive):
96 try:
97 module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf')
98 except zipimport.ZipImportError:
99 pass
100 else:
101 del sys.modules['testconf']
102 if not module:
103 try:
104 with metafile.open() as f:
105 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE))
106 # Handle the case when f is not a true file object but imp requires one
107 except ValueError:
108 # FIXME: 2.5 lacks the delete parameter
109 with tempfile.NamedTemporaryFile(delete=False) as f:
110 inputdatafname = f.name
111 metafile.copy(inputdatafname)
112 with ReadDeleting(inputdatafname) as f:
113 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE))
114 del sys.modules['testconf']
115 module = Config(module, globalconf)
116 if hasattr(module, 'padwithzeroestolength'):
117 if not hasattr(module, 'padtests'):
118 try:
119 module.padtests = module.padwithzeroestolength[0]
120 except TypeError:
121 module.padtests = module.padwithzeroestolength
122 if not hasattr(module, 'paddummies'):
123 try:
124 module.paddummies = module.padwithzeroestolength[1]
125 except TypeError:
126 module.paddummies = module.padwithzeroestolength
127 if (not hasattr(module, 'maxcputime') and
128 not hasattr(module, 'maxwalltime') and
129 hasattr(module, 'maxtime')):
130 module.maxcputime = module.maxtime
131 for name in defaults_problem:
132 setattr(module, name, getattr(module, name, defaults_problem[name]))
133 if not module.dummyinname:
134 module.dummyinname = getattr(module, 'testcaseinname', module.dummyinname)
135 if not module.dummyoutname:
136 module.dummyoutname = getattr(module, 'testcaseoutname', module.dummyoutname)
137 if not hasattr(module, 'path'):
138 if hasattr(module, 'name'):
139 module.path = module.name
140 elif sys.platform != 'win32':
141 module.path = os.path.join(os.path.curdir, problem_name)
142 else:
143 module.path = problem_name
144 for name in 'pointmap', 'groupweight':
145 oldmap = getattr(module, name)
146 if isinstance(oldmap, dict):
147 newmap = {}
148 for key in oldmap:
149 if not options.legacy and isinstance(key, basestring):
150 newmap[key] = oldmap[key]
151 else:
152 try:
153 for k in key:
154 newmap[k] = oldmap[key]
155 except TypeError:
156 newmap[key] = oldmap[key]
157 setattr(module, name, newmap)
158 if options.no_maxtime:
159 module.maxcputime = module.maxwalltime = 0
160 try:
161 sys.dont_write_bytecode = dwb
162 except NameError:
163 pass
164 for name in patterns:
165 if hasattr(module, name):
166 setattr(module, name, getattr(module, name).replace('%', problem_name))
167 return module
168
169 def load_global():
170 global builtins
171 try:
172 dwb = sys.dont_write_bytecode
173 sys.dont_write_bytecode = True
174 except AttributeError:
175 pass
176 metafile = files.File('testconf.py', True, 'configuration')
177 module = None
178 with CompatBuiltins() as builtins:
179 if zipimport and isinstance(metafile.archive, files.ZipArchive):
180 try:
181 module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf')
182 except zipimport.ZipImportError:
183 pass
184 else:
185 del sys.modules['testconf']
186 if not module:
187 try:
188 with metafile.open() as f:
189 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE))
190 # Handle the case when f is not a true file object but imp requires one
191 except ValueError:
192 # FIXME: 2.5 lacks the delete parameter
193 with tempfile.NamedTemporaryFile(delete=False) as f:
194 inputdatafname = f.name
195 metafile.copy(inputdatafname)
196 with ReadDeleting(inputdatafname) as f:
197 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE))
198 del sys.modules['testconf']
199 for name in defaults_global:
200 setattr(module, name, getattr(module, name, defaults_global[name]))
201 if not options.erase:
202 for name in defaults_noerase:
203 setattr(module, name, getattr(module, name, defaults_noerase[name]))
204 if hasattr(module, 'tasknames'):
205 module.problems = module.tasknames
206 global globalconf
207 globalconf = module
208 try:
209 sys.dont_write_bytecode = dwb
210 except NameError:
211 pass
212 return module