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
44 # Build tools and packaging
49 'nosetests', # Command line tool
50 'nose', # Python package
52 'sqlite3', # Command line tool
53 'sqlite3-python', # Python package
69 class DependencyError (Exception):
70 def __init__(self, checker, message):
71 self.checker = checker
72 self.message = message
75 return 'check for {0} failed:\n{1}'.format(
76 self.checker.full_name(), self.message)
79 def check(checks=None):
84 checker = CHECKER[check]
85 _sys.stdout.write('check {0}...\t'.format(checker.full_name()))
88 except DependencyError as e:
90 _sys.stdout.write('fail\n')
92 _sys.stdout.write('pass\n')
95 for failure in failures:
102 class Dependency (object):
103 def __init__(self, name, long_name=None, minimum_version=None,
104 version_delimiter='.'):
106 self.long_name = long_name or name
107 self.minimum_version = minimum_version
108 self.version_delimiter = version_delimiter
111 return '<{0} {1}>'.format(type(self).__name__, self.name)
114 if self.name == self.long_name:
117 return '{0} ({1})'.format(self.long_name, self.name)
120 version = self._get_version()
121 parsed_version = None
122 if hasattr(self, '_get_parsed_version'):
123 parsed_version = self._get_parsed_version()
124 if self.minimum_version:
125 self._check_version(version=version, parsed_version=parsed_version)
127 def _get_version(self):
128 raise NotImplementedError(self)
130 def _check_version(self, version, parsed_version=None):
131 if not parsed_version:
132 parsed_version = self._parse_version(version=version)
133 if parsed_version < self.minimum_version:
134 raise DependencyError(
136 message='outdated version of {0}: {1} (need >= {2})'.format(
137 self.full_name(), version,
138 self.version_delimiter.join(
139 str(part) for part in self.minimum_version)))
141 def _parse_version(self, version):
143 for part in version.split(self.version_delimiter):
145 parsed_version.append(int(part))
146 except ValueError as e:
147 raise NotImplementedError((version, part)) from e
148 return tuple(parsed_version)
151 class PythonDependency (Dependency):
152 def __init__(self, name='python', long_name='Python version',
153 minimum_version=(2, 6), **kwargs):
154 super(PythonDependency, self).__init__(
155 name=name, long_name=long_name, minimum_version=minimum_version,
158 def _get_version(self):
161 def _get_parsed_version(self):
162 return _sys.version_info
165 CHECKER['python'] = PythonDependency()
168 class CommandDependency (Dependency):
169 def __init__(self, command, version_option='--version',
170 version_regexp=None, version_stream='stdout', **kwargs):
171 if 'name' not in kwargs:
172 kwargs['name'] = command
173 super(CommandDependency, self).__init__(**kwargs)
174 self.command = command
175 self.version_option = version_option
176 if not version_regexp:
177 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
178 version_regexp = _re.compile(regexp)
179 self.version_regexp = version_regexp
180 self.version_stream = version_stream
182 def _get_version_stream(self):
184 p = _subprocess.Popen(
185 [self.command, self.version_option],
186 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
187 close_fds=True, shell=False, universal_newlines=True)
189 raise DependencyError(
191 message="could not find '{0}' executable".format(self.command),
193 stdout,stderr = p.communicate()
197 "failed to execute '{0} {1}':".format(
198 self.command, self.version_option),
199 'status: {0}'.format(status),
201 for name,string in [('stdout', stdout), ('stderr', stderr)]:
203 lines.extend([name + ':', string])
204 raise DependencyError(checker=self, message='\n'.join(lines))
205 for name,string in [('stdout', stdout), ('stderr', stderr)]:
206 if name == self.version_stream:
208 raise NotImplementedError(self.version_stream)
210 def _get_version(self):
211 version_stream = self._get_version_stream()
212 match = self.version_regexp.search(version_stream)
214 raise DependencyError(
216 message='no version string in output:\n{0}'.format(
218 return match.group(1)
221 for command,long_name,minimum_version in [
222 ('bash', 'Bourne Again Shell', (4, 0)),
223 ('easy_install', 'Setuptools easy_install', None),
224 ('git', 'Git', (1, 8, 0)),
225 ('hg', 'Mercurial', (2, 0, 0)),
226 ('make', None, None),
227 ('sqlite3', 'SQLite 3', None),
228 ('nosetests', 'Nose', (1, 0, 0)),
229 ('emacs', 'Emacs', None),
230 ('xemacs', 'XEmacs', None),
231 ('vim', 'Vim', None),
233 ('nano', 'Nano', None),
234 ('kate', 'Kate', None),
235 ('notepad++', 'Notepad++', None),
236 ('firefox', 'Firefox', None),
237 ('google-chrome', 'Google Chrome', None),
238 ('chromium', 'Chromium', None),
242 CHECKER[command] = CommandDependency(
243 command=command, long_name=long_name, minimum_version=minimum_version)
244 del command, long_name, minimum_version # cleanup namespace
247 class PythonPackageDependency (Dependency):
248 def __init__(self, package, **kwargs):
249 if 'name' not in kwargs:
250 kwargs['name'] = package
251 super(PythonPackageDependency, self).__init__(**kwargs)
252 self.package = package
254 def _get_version(self):
256 package = _importlib.import_module(self.package)
257 except ImportError as e:
258 raise DependencyError(
260 message="could not import the '{0}' package".format(
264 version = package.__version__
265 except AttributeError:
270 for package,name,long_name,minimum_version in [
271 ('mercurial', None, 'Mercurial Python package',
272 CHECKER['hg'].minimum_version),
273 ('nose', None, 'Nose Python package',
274 CHECKER['nosetests'].minimum_version),
275 ('sqlite3', 'sqlite3-python', 'SQLite Python package',
276 CHECKER['sqlite3'].minimum_version),
277 ('IPython', None, None, None),
278 ('numpy', None, 'NumPy', None),
279 ('scipy', None, 'SciPy', None),
280 ('matplotlib', None, 'Matplotlib', None),
281 ('sympy', None, 'SymPy', None),
282 ('Cython', None, None, None),
283 ('networkx', None, 'NetworkX', None),
284 ('mayavi.mlab', None, 'MayaVi', None),
285 ('setuptools', None, 'Setuptools', None),
291 CHECKER[name] = PythonPackageDependency(
292 package=package, name=name, long_name=long_name,
293 minimum_version=minimum_version)
294 del package, name, long_name, minimum_version # cleanup namespace
297 def print_system_info():
298 print("If you do not understand why the above failures occurred,")
299 print("copy and send the *entire* output (all info above and summary")
300 print("below) to the instructor for help.")
302 print('==================')
303 print('System information')
304 print('==================')
305 print('os.name : {0}'.format(_os.name))
307 print('os.uname : {0}'.format(_os.uname()))
310 print('platform : {0}'.format(_sys.platform))
311 print('platform+ : {0}'.format(_platform.platform()))
312 print('prefix : {0}'.format(_sys.prefix))
313 print('exec_prefix : {0}'.format(_sys.exec_prefix))
314 print('executable : {0}'.format(_sys.executable))
315 print('version_info : {0}'.format(_sys.version_info))
316 print('version : {0}'.format(_sys.version))
317 print('environment :')
318 for key,value in sorted(_os.environ.items()):
319 print(' {0}={1}'.format(key, value))
320 print('==================')
323 if __name__ == '__main__':
324 if not check(_sys.argv[1:]):