-
Notifications
You must be signed in to change notification settings - Fork 0
/
testconfig.py
159 lines (130 loc) · 5.67 KB
/
testconfig.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from nose.plugins.base import Plugin
from nose.util import tolist
import os
import configparser
import logging
import codecs
log = logging.getLogger(__name__)
warning = "Cannot access the test config because the plugin has not \
been activated. Did you specify --tc or any other command line option?"
config = {}
def load_yaml(yaml_file, encoding):
""" Load the passed in yaml configuration file """
try:
import yaml
except (ImportError):
raise Exception('unable to import YAML package. Can not continue.')
global config
config = yaml.load(codecs.open(yaml_file, 'r', encoding).read())
def load_ini(ini_file, encoding):
""" Parse and collapse a ConfigParser-Style ini file into a nested,
eval'ing the individual values, as they are assumed to be valid
python statement formatted """
import configparser
global config
tmpconfig = configparser.ConfigParser()
with codecs.open(ini_file, 'r', encoding) as f:
tmpconfig.readfp(f)
config = {}
for section in tmpconfig.sections():
config[section] = {}
for option in tmpconfig.options(section):
config[section][option] = tmpconfig.get(section, option)
def load_python(py_file, encoding):
""" This will exec the defined python file into the config variable -
the implicit assumption is that the python is safe, well formed and will
not do anything bad. This is also dangerous. """
exec(codecs.open(py_file, 'r', encoding).read())
def load_json(json_file, encoding):
""" This will use the json module to to read in the config json file.
"""
import json
global config
with codecs.open(json_file, 'r', encoding=encoding) as handle:
config = json.load(handle)
class TestConfig(Plugin):
enabled = False
name = "test_config"
score = 1
env_opt = "NOSE_TEST_CONFIG_FILE"
format = "ini"
encoding = 'utf-8'
valid_loaders = { 'yaml' : load_yaml, 'ini' : load_ini,
'python' : load_python, 'json': load_json }
def options(self, parser, env=os.environ):
""" Define the command line options for the plugin. """
parser.add_option(
"--tc-file", action="store",
default=env.get(self.env_opt),
dest="testconfig",
help="Configuration file to parse and pass to tests"
" [NOSE_TEST_CONFIG_FILE]")
parser.add_option(
"--tc-file-encoding", action="store",
default=env.get('NOSE_TEST_CONFIG_FILE_ENCODING') or self.encoding,
dest="testconfigencoding",
help="Test config file encoding, default is utf-8"
" [NOSE_TEST_CONFIG_FILE_ENCODING]")
parser.add_option(
"--tc-format", action="store",
default=env.get('NOSE_TEST_CONFIG_FILE_FORMAT') or self.format,
dest="testconfigformat",
help="Test config file format, default is configparser ini format"
" [NOSE_TEST_CONFIG_FILE_FORMAT]")
parser.add_option(
"--tc", action="append",
dest="overrides",
default = [],
help="Option:Value specific overrides.")
parser.add_option(
"--tc-exact", action="store_true",
dest="exact",
default = False,
help="Optional: Do not explode periods in override keys to "
"individual keys within the config dict, instead treat them"
" as config[my.toplevel.key] ala sqlalchemy.url in pylons")
def configure(self, options, noseconfig):
""" Call the super and then validate and call the relevant parser for
the configuration file passed in """
if not options.testconfig and not options.overrides:
return
Plugin.configure(self, options, noseconfig)
self.config = noseconfig
if not options.capture:
self.enabled = False
if options.testconfigformat:
self.format = options.testconfigformat
if self.format not in list(self.valid_loaders.keys()):
raise Exception('%s is not a valid configuration file format' \
% self.format)
# Load the configuration file:
if options.testconfig:
self.valid_loaders[self.format](options.testconfig,
options.testconfigencoding)
overrides = tolist(options.overrides) or []
for override in overrides:
keys, val = override.split(":", 1)
if options.exact:
config[keys] = val
else:
# Create all *parent* keys that may not exist in the config
section = config
keys = keys.split('.')
for key in keys[:-1]:
if key not in section:
section[key] = {}
section = section[key]
# Finally assign the value to the last key
key = keys[-1]
section[key] = val
# Use an environment hack to allow people to set a config file to auto-load
# in case they want to put tests they write through pychecker or any other
# syntax thing which does an execute on the file.
if 'NOSE_TESTCONFIG_AUTOLOAD_YAML' in os.environ:
load_yaml(os.environ['NOSE_TESTCONFIG_AUTOLOAD_YAML'])
if 'NOSE_TESTCONFIG_AUTOLOAD_INI' in os.environ:
load_ini(os.environ['NOSE_TESTCONFIG_AUTOLOAD_INI'])
if 'NOSE_TESTCONFIG_AUTOLOAD_PYTHON' in os.environ:
load_python(os.environ['NOSE_TESTCONFIG_AUTOLOAD_PYTHON'])
if 'NOSE_TESTCONFIG_AUTOLOAD_JSON' in os.environ:
load_json(os.environ['NOSE_TESTCONFIG_AUTOLOAD_JSON'])