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 distutils.ccompiler as _distutils_ccompiler
26 import importlib as _importlib
27 import logging as _logging
29 import platform as _platform
31 import subprocess as _subprocess
37 # Comment out any entries you don't need
47 'hg', # Command line tool
48 'mercurial', # Python package
49 # Build tools and packaging
54 'nosetests', # Command line tool
55 'nose', # Python package
57 'sqlite3', # Command line tool
58 'sqlite3-python', # Python package
74 class DependencyError (Exception):
75 def __init__(self, checker, message):
76 self.checker = checker
77 self.message = message
80 return 'check for {0} failed:\n{1}'.format(
81 self.checker.full_name(), self.message)
84 def check(checks=None):
89 checker = CHECKER[check]
90 _sys.stdout.write('check {0}...\t'.format(checker.full_name()))
93 except DependencyError as e:
95 _sys.stdout.write('fail\n')
97 _sys.stdout.write('pass\n')
100 for failure in failures:
107 class Dependency (object):
108 def __init__(self, name, long_name=None, minimum_version=None,
109 version_delimiter='.', and_dependencies=None,
110 or_dependencies=None):
112 self.long_name = long_name or name
113 self.minimum_version = minimum_version
114 self.version_delimiter = version_delimiter
115 if not and_dependencies:
116 and_dependencies = []
117 self.and_dependencies = and_dependencies
118 if not or_dependencies:
120 self.or_dependencies = or_dependencies
121 self._check_error = None
124 return '<{0} {1}>'.format(type(self).__name__, self.name)
127 if self.name == self.long_name:
130 return '{0} ({1})'.format(self.long_name, self.name)
133 if self._check_error:
134 raise self._check_error
136 self._check_dependencies()
138 except DependencyError as e:
139 self._check_error = e # cache for future calls
142 def _check_dependencies(self):
143 for dependency in self.and_dependencies:
144 if not hasattr(dependency, 'check'):
145 dependency = CHECKER[dependency]
147 or_pass = not bool(self.or_dependencies)
149 for dependency in self.or_dependencies:
150 if not hasattr(dependency, 'check'):
151 dependency = CHECKER[dependency]
154 except DependencyError as e:
163 version = self._get_version()
164 parsed_version = None
165 if hasattr(self, '_get_parsed_version'):
166 parsed_version = self._get_parsed_version()
167 if self.minimum_version:
168 self._check_version(version=version, parsed_version=parsed_version)
170 def _get_version(self):
171 raise NotImplementedError(self)
173 def _check_version(self, version, parsed_version=None):
174 if not parsed_version:
175 parsed_version = self._parse_version(version=version)
176 if parsed_version < self.minimum_version:
177 raise DependencyError(
179 message='outdated version of {0}: {1} (need >= {2})'.format(
180 self.full_name(), version,
181 self.version_delimiter.join(
182 str(part) for part in self.minimum_version)))
184 def _parse_version(self, version):
186 for part in version.split(self.version_delimiter):
188 parsed_version.append(int(part))
189 except ValueError as e:
190 raise NotImplementedError((version, part)) from e
191 return tuple(parsed_version)
194 class PythonDependency (Dependency):
195 def __init__(self, name='python', long_name='Python version',
196 minimum_version=(2, 6), **kwargs):
197 super(PythonDependency, self).__init__(
198 name=name, long_name=long_name, minimum_version=minimum_version,
201 def _get_version(self):
204 def _get_parsed_version(self):
205 return _sys.version_info
208 CHECKER['python'] = PythonDependency()
211 class CommandDependency (Dependency):
212 exe_extension = _distutils_ccompiler.new_compiler().exe_extension
214 def __init__(self, command, version_option='--version',
215 version_regexp=None, version_stream='stdout', **kwargs):
216 if 'name' not in kwargs:
217 kwargs['name'] = command
218 super(CommandDependency, self).__init__(**kwargs)
219 self.command = command
220 self.version_option = version_option
221 if not version_regexp:
222 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
223 version_regexp = _re.compile(regexp)
224 self.version_regexp = version_regexp
225 self.version_stream = version_stream
227 def _get_version_stream(self):
228 command = self.command + (self.exe_extension or '')
230 p = _subprocess.Popen(
231 [command, self.version_option],
232 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
233 close_fds=True, shell=False, universal_newlines=True)
235 raise DependencyError(
237 message="could not find '{0}' executable".format(command),
239 stdout,stderr = p.communicate()
243 "failed to execute '{0} {1}':".format(
244 command, self.version_option),
245 'status: {0}'.format(status),
247 for name,string in [('stdout', stdout), ('stderr', stderr)]:
249 lines.extend([name + ':', string])
250 raise DependencyError(checker=self, message='\n'.join(lines))
251 for name,string in [('stdout', stdout), ('stderr', stderr)]:
252 if name == self.version_stream:
254 raise NotImplementedError(self.version_stream)
256 def _get_version(self):
257 version_stream = self._get_version_stream()
258 match = self.version_regexp.search(version_stream)
260 raise DependencyError(
262 message='no version string in output:\n{0}'.format(
264 return match.group(1)
267 for command,long_name,minimum_version in [
268 ('bash', 'Bourne Again Shell', (4, 0)),
269 ('easy_install', 'Setuptools easy_install', None),
270 ('git', 'Git', (1, 8, 0)),
271 ('hg', 'Mercurial', (2, 0, 0)),
272 ('make', None, None),
273 ('sqlite3', 'SQLite 3', None),
274 ('nosetests', 'Nose', (1, 0, 0)),
275 ('emacs', 'Emacs', None),
276 ('xemacs', 'XEmacs', None),
277 ('vim', 'Vim', None),
279 ('nano', 'Nano', None),
280 ('kate', 'Kate', None),
281 ('notepad++', 'Notepad++', None),
282 ('firefox', 'Firefox', None),
283 ('google-chrome', 'Google Chrome', None),
284 ('chromium', 'Chromium', None),
288 CHECKER[command] = CommandDependency(
289 command=command, long_name=long_name, minimum_version=minimum_version)
290 del command, long_name, minimum_version # cleanup namespace
293 class PythonPackageDependency (Dependency):
294 def __init__(self, package, **kwargs):
295 if 'name' not in kwargs:
296 kwargs['name'] = package
297 if 'and_dependencies' not in kwargs:
298 kwargs['and_dependencies'] = []
299 if 'python' not in kwargs['and_dependencies']:
300 kwargs['and_dependencies'].append('python')
301 super(PythonPackageDependency, self).__init__(**kwargs)
302 self.package = package
304 def _get_version(self):
306 package = _importlib.import_module(self.package)
307 except ImportError as e:
308 raise DependencyError(
310 message="could not import the '{0}' package".format(
314 version = package.__version__
315 except AttributeError:
320 for package,name,long_name,minimum_version in [
321 ('mercurial', None, 'Mercurial Python package',
322 CHECKER['hg'].minimum_version),
323 ('nose', None, 'Nose Python package',
324 CHECKER['nosetests'].minimum_version),
325 ('sqlite3', 'sqlite3-python', 'SQLite Python package',
326 CHECKER['sqlite3'].minimum_version),
327 ('IPython', None, None, None),
328 ('numpy', None, 'NumPy', None),
329 ('scipy', None, 'SciPy', None),
330 ('matplotlib', None, 'Matplotlib', None),
331 ('sympy', None, 'SymPy', None),
332 ('Cython', None, None, None),
333 ('networkx', None, 'NetworkX', None),
334 ('mayavi.mlab', None, 'MayaVi', None),
335 ('setuptools', None, 'Setuptools', None),
341 CHECKER[name] = PythonPackageDependency(
342 package=package, name=name, long_name=long_name,
343 minimum_version=minimum_version)
344 del package, name, long_name, minimum_version # cleanup namespace
347 class VirtualDependency (Dependency):
352 for name,dependencies in [
362 ('virtual-browser', (
368 CHECKER[name] = VirtualDependency(
369 name=name, long_name=name, or_dependencies=dependencies)
370 del name, dependencies # cleanup namespace
373 def print_system_info():
374 print("If you do not understand why the above failures occurred,")
375 print("copy and send the *entire* output (all info above and summary")
376 print("below) to the instructor for help.")
378 print('==================')
379 print('System information')
380 print('==================')
381 print('os.name : {0}'.format(_os.name))
383 print('os.uname : {0}'.format(_os.uname()))
386 print('platform : {0}'.format(_sys.platform))
387 print('platform+ : {0}'.format(_platform.platform()))
388 print('prefix : {0}'.format(_sys.prefix))
389 print('exec_prefix : {0}'.format(_sys.exec_prefix))
390 print('executable : {0}'.format(_sys.executable))
391 print('version_info : {0}'.format(_sys.version_info))
392 print('version : {0}'.format(_sys.version))
393 print('environment :')
394 for key,value in sorted(_os.environ.items()):
395 print(' {0}={1}'.format(key, value))
396 print('==================')
399 if __name__ == '__main__':
400 if not check(_sys.argv[1:]):