3 """Test script to check for required functionality.
5 Execute this code at the command line by typing:
7 python swc-installation-test-2.py
9 How to get a command line:
11 - On OSX run this with the Terminal application.
13 - On Windows, go to the Start menu, select 'Run' and type 'cmd'
14 (without the quotes) to run the 'cmd.exe' Windows Command Prompt.
16 - On Linux, either use your login shell directly, or run one of a
17 number of graphical terminals (e.g. 'xterm', 'gnome-terminal', ...).
19 Run the script and follow the instructions it prints at the end.
21 This script requires at least Python 2.6. You can check the version
22 of Python that you have installed with 'swc-installation-test-1.py'.
25 import importlib as _importlib
26 import logging as _logging
28 import platform as _platform
30 import subprocess as _subprocess
36 # Comment out any entries you don't need
42 'hg', # Command line tool
43 'mercurial', # Python package
45 'nosetests', # Command line tool
46 'nose', # Python package
47 'sqlite3', # Command line tool
48 'sqlite3-python', # Python package
63 class DependencyError (Exception):
64 def __init__(self, checker, message):
65 self.checker = checker
66 self.message = message
69 return 'check for {0} failed:\n{1}'.format(
70 self.checker.full_name(), self.message)
73 def check(checks=None):
78 checker = CHECKER[check]
79 _sys.stdout.write('check {0}...\t'.format(checker.full_name()))
82 except DependencyError as e:
84 _sys.stdout.write('fail\n')
86 _sys.stdout.write('pass\n')
89 for failure in failures:
96 class Dependency (object):
97 def __init__(self, name, long_name=None, minimum_version=None,
98 version_delimiter='.'):
100 self.long_name = long_name or name
101 self.minimum_version = minimum_version
102 self.version_delimiter = version_delimiter
105 return '<{0} {1}>'.format(type(self).__name__, self.name)
108 if self.name == self.long_name:
111 return '{0} ({1})'.format(self.long_name, self.name)
114 version = self._get_version()
115 parsed_version = None
116 if hasattr(self, '_get_parsed_version'):
117 parsed_version = self._get_parsed_version()
118 if self.minimum_version:
119 self._check_version(version=version, parsed_version=parsed_version)
121 def _get_version(self):
122 raise NotImplementedError(self)
124 def _check_version(self, version, parsed_version=None):
125 if not parsed_version:
126 parsed_version = self._parse_version(version=version)
127 if parsed_version < self.minimum_version:
128 raise DependencyError(
130 message='outdated version of {0}: {1} (need >= {2})'.format(
131 self.full_name(), version,
132 self.version_delimiter.join(
133 str(part) for part in self.minimum_version)))
135 def _parse_version(self, version):
137 for part in version.split(self.version_delimiter):
139 parsed_version.append(int(part))
140 except ValueError as e:
141 raise NotImplementedError((version, part)) from e
142 return tuple(parsed_version)
145 class PythonDependency (Dependency):
146 def __init__(self, name='python', long_name='Python version',
147 minimum_version=(2, 6), **kwargs):
148 super(PythonDependency, self).__init__(
149 name=name, long_name=long_name, minimum_version=minimum_version,
152 def _get_version(self):
155 def _get_parsed_version(self):
156 return _sys.version_info
159 CHECKER['python'] = PythonDependency()
162 class CommandDependency (Dependency):
163 def __init__(self, command, version_option='--version',
164 version_regexp=None, version_stream='stdout', **kwargs):
165 if 'name' not in kwargs:
166 kwargs['name'] = command
167 super(CommandDependency, self).__init__(**kwargs)
168 self.command = command
169 self.version_option = version_option
170 if not version_regexp:
171 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
172 version_regexp = _re.compile(regexp)
173 self.version_regexp = version_regexp
174 self.version_stream = version_stream
176 def _get_version_stream(self):
178 p = _subprocess.Popen(
179 [self.command, self.version_option],
180 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
181 close_fds=True, shell=False, universal_newlines=True)
183 raise DependencyError(
185 message="could not find '{0}' executable".format(self.command),
187 stdout,stderr = p.communicate()
191 "failed to execute '{0} {1}':".format(
192 self.command, self.version_option),
193 'status: {0}'.format(status),
195 for name,string in [('stdout', stdout), ('stderr', stderr)]:
197 lines.extend([name + ':', string])
198 raise DependencyError(checker=self, message='\n'.join(lines))
199 for name,string in [('stdout', stdout), ('stderr', stderr)]:
200 if name == self.version_stream:
202 raise NotImplementedError(self.version_stream)
204 def _get_version(self):
205 version_stream = self._get_version_stream()
206 match = self.version_regexp.search(version_stream)
208 raise DependencyError(
210 message='no version string in output:\n{0}'.format(
212 return match.group(1)
215 for command,long_name,minimum_version in [
216 ('bash', 'Bourne Again Shell', (4, 0)),
217 ('easy_install', 'Setuptools easy_install', None),
218 ('git', 'Git', (1, 8, 0)),
219 ('hg', 'Mercurial', (2, 0, 0)),
220 ('make', None, None),
221 ('sqlite3', 'SQLite 3', None),
222 ('nosetests', 'Nose', (1, 0, 0)),
226 CHECKER[command] = CommandDependency(
227 command=command, long_name=long_name, minimum_version=minimum_version)
228 del command, long_name, minimum_version # cleanup namespace
231 class PythonPackageDependency (Dependency):
232 def __init__(self, package, **kwargs):
233 if 'name' not in kwargs:
234 kwargs['name'] = package
235 super(PythonPackageDependency, self).__init__(**kwargs)
236 self.package = package
238 def _get_version(self):
240 package = _importlib.import_module(self.package)
241 except ImportError as e:
242 raise DependencyError(
244 message="could not import the '{0}' package".format(
248 version = package.__version__
249 except AttributeError:
254 for package,name,long_name,minimum_version in [
255 ('mercurial', None, 'Mercurial Python package',
256 CHECKER['hg'].minimum_version),
257 ('nose', None, 'Nose Python package',
258 CHECKER['nosetests'].minimum_version),
259 ('sqlite3', 'sqlite3-python', 'SQLite Python package',
260 CHECKER['sqlite3'].minimum_version),
261 ('IPython', None, None, None),
262 ('numpy', None, 'NumPy', None),
263 ('scipy', None, 'SciPy', None),
264 ('matplotlib', None, 'Matplotlib', None),
265 ('sympy', None, 'SymPy', None),
266 ('Cython', None, None, None),
267 ('networkx', None, 'NetworkX', None),
268 ('mayavi.mlab', None, 'MayaVi', None),
269 ('setuptools', None, 'Setuptools', None),
275 CHECKER[name] = PythonPackageDependency(
276 package=package, name=name, long_name=long_name,
277 minimum_version=minimum_version)
278 del package, name, long_name, minimum_version # cleanup namespace
281 def print_system_info():
282 print("If you do not understand why the above failures occurred,")
283 print("copy and send the *entire* output (all info above and summary")
284 print("below) to the instructor for help.")
286 print('==================')
287 print('System information')
288 print('==================')
289 print('os.name : {0}'.format(_os.name))
291 print('os.uname : {0}'.format(_os.uname()))
294 print('platform : {0}'.format(_sys.platform))
295 print('platform+ : {0}'.format(_platform.platform()))
296 print('prefix : {0}'.format(_sys.prefix))
297 print('exec_prefix : {0}'.format(_sys.exec_prefix))
298 print('executable : {0}'.format(_sys.executable))
299 print('version_info : {0}'.format(_sys.version_info))
300 print('version : {0}'.format(_sys.version))
301 print('environment :')
302 for key,value in sorted(_os.environ.items()):
303 print(' {0}={1}'.format(key, value))
304 print('==================')
307 if __name__ == '__main__':
308 if not check(_sys.argv[1:]):