view 2.00/config.py @ 26:5bbb68833868

Output text improvements Detailed error messages are now printed in more cases and have only their first letter forced into lowercase. The description of the --update option now describes properly what it does.
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 23 Sep 2010 23:50:45 +0000
parents b500e117080e
children dc4be35d17e0
line wrap: on
line source

#! /usr/bin/env python
# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>

from __future__ import division, with_statement

try:
	from compat import *
	import files
except ImportError:
	import __main__
	__main__.import_error(sys.exc_info()[1])
else:
	from __main__ import options

if files.ZipArchive:
	try:
		import zipimport
	except ImportError:
		zipimport = None
else:
	zipimport = None

import imp, os, sys, tempfile

__all__ = 'load_problem', 'load_global', 'globalconf'

defaults_problem = {'usegroups': False,
                    'maxtime': None,
                    'maxmemory': None,
                    'dummies': {},
                    'testsexcluded': (),
                    'padtests': 0,
                    'paddummies': 0,
                    'taskweight': 100,
                    'pointmap': {},
                    'stdio': False,
                    'dummyinname': '',
                    'dummyoutname': '',
                    'tester': None,
                    'maxexitcode': 0,
                    'inname': '',
                    'ansname': ''}
defaults_global = {'tasknames': None,
                   'force_zero_exitcode': True}
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 load_problem(problem_name):
	dwb = sys.dont_write_bytecode
	sys.dont_write_bytecode = True
	metafile = files.File('/'.join((problem_name, 'testconf.py')), True, 'configuration')
	module = None
	with CompatBuiltins():
		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']
	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
	for name in defaults_problem:
		if not hasattr(globalconf, name):
			setattr(module, name, getattr(module, name, defaults_problem[name]))
	if 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 options.no_maxtime:
		module.maxtime = 0
	sys.dont_write_bytecode = dwb
	module = Config(module, globalconf)
	for name in patterns:
		if hasattr(module, name):
			setattr(module, name, getattr(module, name).replace('%', problem_name))
	return module

def load_global():
	dwb = sys.dont_write_bytecode
	sys.dont_write_bytecode = True
	metafile = files.File('testconf.py', True, 'configuration')
	module = None
	with CompatBuiltins():
		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]))
	global globalconf
	globalconf = module
	sys.dont_write_bytecode = dwb
	return module