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
123 return '<{0} {1}>'.format(type(self).__name__, self.name)
126 if self.name == self.long_name:
129 return '{0} ({1})'.format(self.long_name, self.name)
132 self._check_dependencies()
135 def _check_dependencies(self):
136 for dependency in self.and_dependencies:
137 if not hasattr(dependency, 'check'):
138 dependency = CHECKER[dependency]
140 or_pass = not bool(self.or_dependencies)
142 for dependency in self.or_dependencies:
143 if not hasattr(dependency, 'check'):
144 dependency = CHECKER[dependency]
147 except DependencyError as e:
156 version = self._get_version()
157 parsed_version = None
158 if hasattr(self, '_get_parsed_version'):
159 parsed_version = self._get_parsed_version()
160 if self.minimum_version:
161 self._check_version(version=version, parsed_version=parsed_version)
163 def _get_version(self):
164 raise NotImplementedError(self)
166 def _check_version(self, version, parsed_version=None):
167 if not parsed_version:
168 parsed_version = self._parse_version(version=version)
169 if parsed_version < self.minimum_version:
170 raise DependencyError(
172 message='outdated version of {0}: {1} (need >= {2})'.format(
173 self.full_name(), version,
174 self.version_delimiter.join(
175 str(part) for part in self.minimum_version)))
177 def _parse_version(self, version):
179 for part in version.split(self.version_delimiter):
181 parsed_version.append(int(part))
182 except ValueError as e:
183 raise NotImplementedError((version, part)) from e
184 return tuple(parsed_version)
187 class PythonDependency (Dependency):
188 def __init__(self, name='python', long_name='Python version',
189 minimum_version=(2, 6), **kwargs):
190 super(PythonDependency, self).__init__(
191 name=name, long_name=long_name, minimum_version=minimum_version,
194 def _get_version(self):
197 def _get_parsed_version(self):
198 return _sys.version_info
201 CHECKER['python'] = PythonDependency()
204 class CommandDependency (Dependency):
205 exe_extension = _distutils_ccompiler.new_compiler().exe_extension
207 def __init__(self, command, version_option='--version',
208 version_regexp=None, version_stream='stdout', **kwargs):
209 if 'name' not in kwargs:
210 kwargs['name'] = command
211 super(CommandDependency, self).__init__(**kwargs)
212 self.command = command
213 self.version_option = version_option
214 if not version_regexp:
215 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
216 version_regexp = _re.compile(regexp)
217 self.version_regexp = version_regexp
218 self.version_stream = version_stream
220 def _get_version_stream(self):
221 command = self.command + (self.exe_extension or '')
223 p = _subprocess.Popen(
224 [command, self.version_option],
225 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
226 close_fds=True, shell=False, universal_newlines=True)
228 raise DependencyError(
230 message="could not find '{0}' executable".format(command),
232 stdout,stderr = p.communicate()
236 "failed to execute '{0} {1}':".format(
237 command, self.version_option),
238 'status: {0}'.format(status),
240 for name,string in [('stdout', stdout), ('stderr', stderr)]:
242 lines.extend([name + ':', string])
243 raise DependencyError(checker=self, message='\n'.join(lines))
244 for name,string in [('stdout', stdout), ('stderr', stderr)]:
245 if name == self.version_stream:
247 raise NotImplementedError(self.version_stream)
249 def _get_version(self):
250 version_stream = self._get_version_stream()
251 match = self.version_regexp.search(version_stream)
253 raise DependencyError(
255 message='no version string in output:\n{0}'.format(
257 return match.group(1)
260 for command,long_name,minimum_version in [
261 ('bash', 'Bourne Again Shell', (4, 0)),
262 ('easy_install', 'Setuptools easy_install', None),
263 ('git', 'Git', (1, 8, 0)),
264 ('hg', 'Mercurial', (2, 0, 0)),
265 ('make', None, None),
266 ('sqlite3', 'SQLite 3', None),
267 ('nosetests', 'Nose', (1, 0, 0)),
268 ('emacs', 'Emacs', None),
269 ('xemacs', 'XEmacs', None),
270 ('vim', 'Vim', None),
272 ('nano', 'Nano', None),
273 ('kate', 'Kate', None),
274 ('notepad++', 'Notepad++', None),
275 ('firefox', 'Firefox', None),
276 ('google-chrome', 'Google Chrome', None),
277 ('chromium', 'Chromium', None),
281 CHECKER[command] = CommandDependency(
282 command=command, long_name=long_name, minimum_version=minimum_version)
283 del command, long_name, minimum_version # cleanup namespace
286 class PythonPackageDependency (Dependency):
287 def __init__(self, package, **kwargs):
288 if 'name' not in kwargs:
289 kwargs['name'] = package
290 super(PythonPackageDependency, self).__init__(**kwargs)
291 self.package = package
293 def _get_version(self):
295 package = _importlib.import_module(self.package)
296 except ImportError as e:
297 raise DependencyError(
299 message="could not import the '{0}' package".format(
303 version = package.__version__
304 except AttributeError:
309 for package,name,long_name,minimum_version in [
310 ('mercurial', None, 'Mercurial Python package',
311 CHECKER['hg'].minimum_version),
312 ('nose', None, 'Nose Python package',
313 CHECKER['nosetests'].minimum_version),
314 ('sqlite3', 'sqlite3-python', 'SQLite Python package',
315 CHECKER['sqlite3'].minimum_version),
316 ('IPython', None, None, None),
317 ('numpy', None, 'NumPy', None),
318 ('scipy', None, 'SciPy', None),
319 ('matplotlib', None, 'Matplotlib', None),
320 ('sympy', None, 'SymPy', None),
321 ('Cython', None, None, None),
322 ('networkx', None, 'NetworkX', None),
323 ('mayavi.mlab', None, 'MayaVi', None),
324 ('setuptools', None, 'Setuptools', None),
330 CHECKER[name] = PythonPackageDependency(
331 package=package, name=name, long_name=long_name,
332 minimum_version=minimum_version)
333 del package, name, long_name, minimum_version # cleanup namespace
336 class VirtualDependency (Dependency):
341 for name,dependencies in [
351 ('virtual-browser', (
357 CHECKER[name] = VirtualDependency(
358 name=name, long_name=name, or_dependencies=dependencies)
359 del name, dependencies # cleanup namespace
362 def print_system_info():
363 print("If you do not understand why the above failures occurred,")
364 print("copy and send the *entire* output (all info above and summary")
365 print("below) to the instructor for help.")
367 print('==================')
368 print('System information')
369 print('==================')
370 print('os.name : {0}'.format(_os.name))
372 print('os.uname : {0}'.format(_os.uname()))
375 print('platform : {0}'.format(_sys.platform))
376 print('platform+ : {0}'.format(_platform.platform()))
377 print('prefix : {0}'.format(_sys.prefix))
378 print('exec_prefix : {0}'.format(_sys.exec_prefix))
379 print('executable : {0}'.format(_sys.executable))
380 print('version_info : {0}'.format(_sys.version_info))
381 print('version : {0}'.format(_sys.version))
382 print('environment :')
383 for key,value in sorted(_os.environ.items()):
384 print(' {0}={1}'.format(key, value))
385 print('==================')
388 if __name__ == '__main__':
389 if not check(_sys.argv[1:]):