Mercurial > ~astiob > upreckon > hgweb
annotate config.py @ 80:809b77302b21
Win32-specific module with memory and CPU time limits
The Win32-specific implementation of call() and friends now lives
in module win32, looks clean and in addition is able to enforce memory
and CPU time limits on NT kernels, in particular on Windows 2000 and up
asking the system to terminate the process as soon as or (in the case
of CPU time) almost as soon as the limits are broken. According to my
observations, malloc() in the limited process does not return NULL
when memory usage is close to the limit and instead crashes the process
(which Upreckon happily translates into 'memory limit exceeded').
The catch is that the module is not actually used yet; coming soon.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Wed, 16 Feb 2011 00:01:33 +0000 |
parents | ee8a99dcaaed |
children | 06356af50bf9 |
rev | line source |
---|---|
21 | 1 #! /usr/bin/env python |
78 | 2 # Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv> |
16 | 3 |
21 | 4 from __future__ import division, with_statement |
5 | |
6 try: | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
7 from compat import * |
21 | 8 import files |
9 except ImportError: | |
10 import __main__ | |
11 __main__.import_error(sys.exc_info()[1]) | |
12 else: | |
13 from __main__ import options | |
14 | |
15 if files.ZipArchive: | |
16 try: | |
17 import zipimport | |
18 except ImportError: | |
19 zipimport = None | |
20 else: | |
21 zipimport = None | |
22 | |
22 | 23 import imp, os, sys, tempfile |
21 | 24 |
25 __all__ = 'load_problem', 'load_global', 'globalconf' | |
26 | |
74 | 27 defaults_problem = {'kind': 'batch', |
28 'usegroups': False, | |
21 | 29 'maxtime': None, |
30 'maxmemory': None, | |
31 'dummies': {}, | |
32 'testsexcluded': (), | |
33 'padtests': 0, | |
34 'paddummies': 0, | |
35 'taskweight': 100, | |
76
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
36 'groupweight': {}, |
21 | 37 'pointmap': {}, |
38 'stdio': False, | |
39 'dummyinname': '', | |
40 'dummyoutname': '', | |
41 'tester': None, | |
42 'maxexitcode': 0, | |
43 'inname': '', | |
44 'ansname': ''} | |
79
ee8a99dcaaed
Renamed configuration variable tasknames to problems
Oleg Oshmyan <chortos@inbox.lv>
parents:
78
diff
changeset
|
45 defaults_global = {'problems': None, |
22 | 46 'force_zero_exitcode': True} |
43 | 47 defaults_noerase = {'inname': '%.in', |
48 'outname': '%.out', | |
49 'ansname': '%.ans'} | |
21 | 50 patterns = ('inname', 'outname', 'ansname', 'testcaseinname', |
51 'testcaseoutname', 'dummyinname', 'dummyoutname') | |
52 | |
53 class Config(object): | |
54 __slots__ = 'modules', '__dict__' | |
55 | |
56 def __init__(self, *modules): | |
57 self.modules = modules | |
58 | |
59 def __getattr__(self, name): | |
60 for module in self.modules: | |
61 try: | |
62 return getattr(module, name) | |
63 except AttributeError: | |
64 pass | |
65 # TODO: provide a message | |
66 raise AttributeError(name) | |
16 | 67 |
22 | 68 # A helper context manager |
69 class ReadDeleting(object): | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
70 __slots__ = 'name', 'file' |
22 | 71 |
72 def __init__(self, name): | |
73 self.name = name | |
74 | |
75 def __enter__(self): | |
76 try: | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
77 self.file = open(self.name, 'rU') |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
78 return self.file |
22 | 79 except: |
80 try: | |
81 self.__exit__(None, None, None) | |
82 except: | |
83 pass | |
84 raise | |
85 | |
86 def __exit__(self, exc_type, exc_val, exc_tb): | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
87 self.file.close() |
22 | 88 os.remove(self.name) |
89 | |
21 | 90 def load_problem(problem_name): |
70
b9d5857f7b9a
Better emulation of built-ins for testconf
Oleg Oshmyan <chortos@inbox.lv>
parents:
60
diff
changeset
|
91 global builtins |
21 | 92 dwb = sys.dont_write_bytecode |
93 sys.dont_write_bytecode = True | |
94 metafile = files.File('/'.join((problem_name, 'testconf.py')), True, 'configuration') | |
95 module = None | |
70
b9d5857f7b9a
Better emulation of built-ins for testconf
Oleg Oshmyan <chortos@inbox.lv>
parents:
60
diff
changeset
|
96 with CompatBuiltins() as builtins: |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
97 if zipimport and isinstance(metafile.archive, files.ZipArchive): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
98 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
99 module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf') |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
100 except zipimport.ZipImportError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
101 pass |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
102 else: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
103 del sys.modules['testconf'] |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
104 if not module: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
105 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
106 with metafile.open() as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
107 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
108 # Handle the case when f is not a true file object but imp requires one |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
109 except ValueError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
110 # FIXME: 2.5 lacks the delete parameter |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
111 with tempfile.NamedTemporaryFile(delete=False) as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
112 inputdatafname = f.name |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
113 metafile.copy(inputdatafname) |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
114 with ReadDeleting(inputdatafname) as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
115 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) |
21 | 116 del sys.modules['testconf'] |
117 if hasattr(module, 'padwithzeroestolength'): | |
118 if not hasattr(module, 'padtests'): | |
119 try: | |
120 module.padtests = module.padwithzeroestolength[0] | |
121 except TypeError: | |
122 module.padtests = module.padwithzeroestolength | |
123 if not hasattr(module, 'paddummies'): | |
124 try: | |
125 module.paddummies = module.padwithzeroestolength[1] | |
126 except TypeError: | |
127 module.paddummies = module.padwithzeroestolength | |
128 for name in defaults_problem: | |
129 if not hasattr(globalconf, name): | |
130 setattr(module, name, getattr(module, name, defaults_problem[name])) | |
38
a6d554679ce8
Fixed a bug with nested configuration namespaces in config.py
Oleg Oshmyan <chortos@inbox.lv>
parents:
27
diff
changeset
|
131 module = Config(module, globalconf) |
27 | 132 if not module.dummyinname: |
133 module.dummyinname = getattr(module, 'testcaseinname', module.dummyinname) | |
134 if not module.dummyoutname: | |
135 module.dummyoutname = getattr(module, 'testcaseoutname', module.dummyoutname) | |
21 | 136 if not hasattr(module, 'path'): |
137 if hasattr(module, 'name'): | |
138 module.path = module.name | |
139 elif sys.platform != 'win32': | |
140 module.path = os.path.join(os.path.curdir, problem_name) | |
141 else: | |
142 module.path = problem_name | |
76
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
143 for name in 'pointmap', 'groupweight': |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
144 oldmap = getattr(module, name) |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
145 if isinstance(oldmap, dict): |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
146 newmap = {} |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
147 for key in oldmap: |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
148 if not options.legacy and isinstance(key, basestring): |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
149 newmap[key] = oldmap[key] |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
150 else: |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
151 try: |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
152 for k in key: |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
153 newmap[k] = oldmap[key] |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
154 except TypeError: |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
155 newmap[key] = oldmap[key] |
0e5ae28e0b2b
Points are now weighted on a test context basis
Oleg Oshmyan <chortos@inbox.lv>
parents:
74
diff
changeset
|
156 setattr(module, name, newmap) |
21 | 157 if options.no_maxtime: |
158 module.maxtime = 0 | |
159 sys.dont_write_bytecode = dwb | |
24
c23d81f4a1a3
Score returned by TestCase.__call__() is now normalized to 0..1
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
160 for name in patterns: |
c23d81f4a1a3
Score returned by TestCase.__call__() is now normalized to 0..1
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
161 if hasattr(module, name): |
c23d81f4a1a3
Score returned by TestCase.__call__() is now normalized to 0..1
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
162 setattr(module, name, getattr(module, name).replace('%', problem_name)) |
c23d81f4a1a3
Score returned by TestCase.__call__() is now normalized to 0..1
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
163 return module |
21 | 164 |
165 def load_global(): | |
70
b9d5857f7b9a
Better emulation of built-ins for testconf
Oleg Oshmyan <chortos@inbox.lv>
parents:
60
diff
changeset
|
166 global builtins |
21 | 167 dwb = sys.dont_write_bytecode |
168 sys.dont_write_bytecode = True | |
169 metafile = files.File('testconf.py', True, 'configuration') | |
170 module = None | |
70
b9d5857f7b9a
Better emulation of built-ins for testconf
Oleg Oshmyan <chortos@inbox.lv>
parents:
60
diff
changeset
|
171 with CompatBuiltins() as builtins: |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
172 if zipimport and isinstance(metafile.archive, files.ZipArchive): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
173 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
174 module = zipimport.zipimporter(os.path.dirname(metafile.full_real_path)).load_module('testconf') |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
175 except zipimport.ZipImportError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
176 pass |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
177 else: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
178 del sys.modules['testconf'] |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
179 if not module: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
180 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
181 with metafile.open() as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
182 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
183 # Handle the case when f is not a true file object but imp requires one |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
184 except ValueError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
185 # FIXME: 2.5 lacks the delete parameter |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
186 with tempfile.NamedTemporaryFile(delete=False) as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
187 inputdatafname = f.name |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
188 metafile.copy(inputdatafname) |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
189 with ReadDeleting(inputdatafname) as f: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
24
diff
changeset
|
190 module = imp.load_module('testconf', f, metafile.full_real_path, ('.py', 'r', imp.PY_SOURCE)) |
21 | 191 del sys.modules['testconf'] |
192 for name in defaults_global: | |
193 setattr(module, name, getattr(module, name, defaults_global[name])) | |
43 | 194 if not options.erase: |
195 for name in defaults_noerase: | |
196 setattr(module, name, getattr(module, name, defaults_noerase[name])) | |
79
ee8a99dcaaed
Renamed configuration variable tasknames to problems
Oleg Oshmyan <chortos@inbox.lv>
parents:
78
diff
changeset
|
197 if hasattr(module, 'tasknames'): |
ee8a99dcaaed
Renamed configuration variable tasknames to problems
Oleg Oshmyan <chortos@inbox.lv>
parents:
78
diff
changeset
|
198 module.problems = module.tasknames |
21 | 199 global globalconf |
200 globalconf = module | |
201 sys.dont_write_bytecode = dwb | |
202 return module |