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 from __future__ import print_function # for Python 2.6 compatibility
27 import distutils.ccompiler as _distutils_ccompiler
28 try: # Python 2.7 and 3.x
29 import importlib as _importlib
30 except ImportError: # Python 2.6 and earlier
31 class _Importlib (object):
32 """Minimal workarounds for functions we need
35 def import_module(name):
36 module = __import__(name)
37 for n in name.split('.')[1:]:
38 module = getattr(module, n)
40 _importlib = _Importlib()
41 import logging as _logging
43 import platform as _platform
45 import subprocess as _subprocess
51 # Comment out any entries you don't need
61 'hg', # Command line tool
62 'mercurial', # Python package
63 # Build tools and packaging
68 'nosetests', # Command line tool
69 'nose', # Python package
71 'sqlite3', # Command line tool
72 'sqlite3-python', # Python package
88 class DependencyError (Exception):
89 def __init__(self, checker, message):
90 self.checker = checker
91 self.message = message
94 return 'check for {0} failed:\n{1}'.format(
95 self.checker.full_name(), self.message)
98 def check(checks=None):
104 checker = CHECKER[check]
105 _sys.stdout.write('check {0}...\t'.format(checker.full_name()))
107 version = checker.check()
108 except DependencyError as e:
110 _sys.stdout.write('fail\n')
112 _sys.stdout.write('pass\n')
113 successes.append((checker, version))
115 print('\nSuccesses:\n')
116 for checker,version in successes:
117 print('{0} {1}'.format(
119 version or 'unknown'))
123 for failure in failures:
124 if failure not in printed:
127 printed.append(failure)
132 class Dependency (object):
133 def __init__(self, name, long_name=None, minimum_version=None,
134 version_delimiter='.', and_dependencies=None,
135 or_dependencies=None):
137 self.long_name = long_name or name
138 self.minimum_version = minimum_version
139 self.version_delimiter = version_delimiter
140 if not and_dependencies:
141 and_dependencies = []
142 self.and_dependencies = and_dependencies
143 if not or_dependencies:
145 self.or_dependencies = or_dependencies
146 self._check_error = None
149 return '<{0} {1}>'.format(type(self).__name__, self.name)
152 if self.name == self.long_name:
155 return '{0} ({1})'.format(self.long_name, self.name)
158 if self._check_error:
159 raise self._check_error
161 self._check_dependencies()
163 except DependencyError as e:
164 self._check_error = e # cache for future calls
167 def _check_dependencies(self):
168 for dependency in self.and_dependencies:
169 if not hasattr(dependency, 'check'):
170 dependency = CHECKER[dependency]
172 self.or_pass = or_error = None
173 for dependency in self.or_dependencies:
174 if not hasattr(dependency, 'check'):
175 dependency = CHECKER[dependency]
177 version = dependency.check()
178 except DependencyError as e:
182 'dependency': dependency,
185 if self.or_dependencies and not self.or_pass:
189 version = self._get_version()
190 parsed_version = None
191 if hasattr(self, '_get_parsed_version'):
192 parsed_version = self._get_parsed_version()
193 if self.minimum_version:
194 self._check_version(version=version, parsed_version=parsed_version)
197 def _get_version(self):
198 raise NotImplementedError(self)
200 def _check_version(self, version, parsed_version=None):
201 if not parsed_version:
202 parsed_version = self._parse_version(version=version)
203 if not parsed_version or parsed_version < self.minimum_version:
204 raise DependencyError(
206 message='outdated version of {0}: {1} (need >= {2})'.format(
207 self.full_name(), version,
208 self.version_delimiter.join(
209 str(part) for part in self.minimum_version)))
211 def _parse_version(self, version):
215 for part in version.split(self.version_delimiter):
217 parsed_version.append(int(part))
218 except ValueError as e:
219 raise NotImplementedError((version, part))# from e
220 return tuple(parsed_version)
223 class PythonDependency (Dependency):
224 def __init__(self, name='python', long_name='Python version',
225 minimum_version=(2, 6), **kwargs):
226 super(PythonDependency, self).__init__(
227 name=name, long_name=long_name, minimum_version=minimum_version,
230 def _get_version(self):
233 def _get_parsed_version(self):
234 return _sys.version_info
237 CHECKER['python'] = PythonDependency()
240 class CommandDependency (Dependency):
241 exe_extension = _distutils_ccompiler.new_compiler().exe_extension
243 def __init__(self, command, version_option='--version',
244 version_regexp=None, version_stream='stdout', **kwargs):
245 if 'name' not in kwargs:
246 kwargs['name'] = command
247 super(CommandDependency, self).__init__(**kwargs)
248 self.command = command
249 self.version_option = version_option
250 if not version_regexp:
251 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
252 version_regexp = _re.compile(regexp)
253 self.version_regexp = version_regexp
254 self.version_stream = version_stream
256 def _get_version_stream(self):
257 command = self.command + (self.exe_extension or '')
259 p = _subprocess.Popen(
260 [command, self.version_option],
261 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
262 close_fds=True, shell=False, universal_newlines=True)
264 raise DependencyError(
266 message="could not find '{0}' executable".format(command),
268 stdout,stderr = p.communicate()
272 "failed to execute '{0} {1}':".format(
273 command, self.version_option),
274 'status: {0}'.format(status),
276 for name,string in [('stdout', stdout), ('stderr', stderr)]:
278 lines.extend([name + ':', string])
279 raise DependencyError(checker=self, message='\n'.join(lines))
280 for name,string in [('stdout', stdout), ('stderr', stderr)]:
281 if name == self.version_stream:
283 raise NotImplementedError(self.version_stream)
285 def _get_version(self):
286 version_stream = self._get_version_stream()
287 match = self.version_regexp.search(version_stream)
289 raise DependencyError(
291 message='no version string in output:\n{0}'.format(
293 return match.group(1)
296 for command,long_name,minimum_version in [
297 ('bash', 'Bourne Again Shell', (4, 0)),
298 ('easy_install', 'Setuptools easy_install', None),
299 ('git', 'Git', (1, 8, 0)),
300 ('hg', 'Mercurial', (2, 0, 0)),
301 ('make', None, None),
302 ('sqlite3', 'SQLite 3', None),
303 ('nosetests', 'Nose', (1, 0, 0)),
304 ('emacs', 'Emacs', None),
305 ('xemacs', 'XEmacs', None),
306 ('vim', 'Vim', None),
308 ('nano', 'Nano', None),
309 ('kate', 'Kate', None),
310 ('notepad++', 'Notepad++', None),
311 ('firefox', 'Firefox', None),
312 ('google-chrome', 'Google Chrome', None),
313 ('chromium', 'Chromium', None),
317 CHECKER[command] = CommandDependency(
318 command=command, long_name=long_name, minimum_version=minimum_version)
319 del command, long_name, minimum_version # cleanup namespace
322 class PythonPackageDependency (Dependency):
323 def __init__(self, package, **kwargs):
324 if 'name' not in kwargs:
325 kwargs['name'] = package
326 if 'and_dependencies' not in kwargs:
327 kwargs['and_dependencies'] = []
328 if 'python' not in kwargs['and_dependencies']:
329 kwargs['and_dependencies'].append('python')
330 super(PythonPackageDependency, self).__init__(**kwargs)
331 self.package = package
333 def _get_version(self):
334 package = self._get_package(self.package)
335 return self._get_version_from_package(package)
337 def _get_package(self, package):
339 return _importlib.import_module(package)
340 except ImportError as e:
341 raise DependencyError(
343 message="could not import the '{0}' package for {1}".format(
344 package, self.full_name()),
347 def _get_version_from_package(self, package):
349 version = package.__version__
350 except AttributeError:
355 for package,name,long_name,minimum_version in [
356 ('nose', None, 'Nose Python package',
357 CHECKER['nosetests'].minimum_version),
358 ('sqlite3', 'sqlite3-python', 'SQLite Python package',
359 CHECKER['sqlite3'].minimum_version),
360 ('IPython', None, None, None),
361 ('numpy', None, 'NumPy', None),
362 ('scipy', None, 'SciPy', None),
363 ('matplotlib', None, 'Matplotlib', None),
364 ('sympy', None, 'SymPy', None),
365 ('Cython', None, None, None),
366 ('networkx', None, 'NetworkX', None),
367 ('mayavi.mlab', None, 'MayaVi', None),
368 ('setuptools', None, 'Setuptools', None),
374 CHECKER[name] = PythonPackageDependency(
375 package=package, name=name, long_name=long_name,
376 minimum_version=minimum_version)
377 del package, name, long_name, minimum_version # cleanup namespace
380 class MercurialPythonPackage (PythonPackageDependency):
381 def _get_version(self):
382 try: # mercurial >= 1.2
383 package = _importlib.import_module('mercurial.util')
384 except ImportError as e: # mercurial <= 1.1.2
385 package = self._get_package('mercurial.version')
386 return package.get_version()
388 return package.version()
391 CHECKER['mercurial'] = MercurialPythonPackage(
392 package='mercurial.util', name='mercurial',
393 long_name='Mercurial Python package',
394 minimum_version=CHECKER['hg'].minimum_version)
397 class VirtualDependency (Dependency):
399 return '{0} {1}'.format(
400 self.or_pass['dependency'].full_name(),
401 self.or_pass['version'])
404 for name,dependencies in [
414 ('virtual-browser', (
420 CHECKER[name] = VirtualDependency(
421 name=name, long_name=name, or_dependencies=dependencies)
422 del name, dependencies # cleanup namespace
425 def print_system_info():
426 print("If you do not understand why the above failures occurred,")
427 print("copy and send the *entire* output (all info above and summary")
428 print("below) to the instructor for help.")
430 print('==================')
431 print('System information')
432 print('==================')
433 print('os.name : {0}'.format(_os.name))
435 print('os.uname : {0}'.format(_os.uname()))
438 print('platform : {0}'.format(_sys.platform))
439 print('platform+ : {0}'.format(_platform.platform()))
440 print('prefix : {0}'.format(_sys.prefix))
441 print('exec_prefix : {0}'.format(_sys.exec_prefix))
442 print('executable : {0}'.format(_sys.executable))
443 print('version_info : {0}'.format(_sys.version_info))
444 print('version : {0}'.format(_sys.version))
445 print('environment :')
446 for key,value in sorted(_os.environ.items()):
447 print(' {0}={1}'.format(key, value))
448 print('==================')
451 if __name__ == '__main__':
452 if not check(_sys.argv[1:]):