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 Run the script and follow the instructions it prints at the end.
11 This script requires at least Python 2.6. You can check the version
12 of Python that you have installed with 'swc-installation-test-1.py'.
14 By default, this script will test for all the dependencies your
15 instructor thinks you need. If you want to test for a different set
16 of packages, you can list them on the command line. For example:
18 python swc-installation-test-2.py git virtual-editor
20 This is useful if the original test told you to install a more recent
21 version of a particular dependency, and you just want to re-test that
25 from __future__ import print_function # for Python 2.6 compatibility
27 import distutils.ccompiler as _distutils_ccompiler
28 import fnmatch as _fnmatch
29 try: # Python 2.7 and 3.x
30 import importlib as _importlib
31 except ImportError: # Python 2.6 and earlier
32 class _Importlib (object):
33 """Minimal workarounds for functions we need
36 def import_module(name):
37 module = __import__(name)
38 for n in name.split('.')[1:]:
39 module = getattr(module, n)
41 _importlib = _Importlib()
42 import logging as _logging
44 import platform as _platform
46 import shlex as _shlex
47 import subprocess as _subprocess
50 import urllib.parse as _urllib_parse
51 except ImportError: # Python 2.x
52 import urllib as _urllib_parse # for quote()
55 if not hasattr(_shlex, 'quote'): # Python versions older than 3.3
56 # Use the undocumented pipes.quote()
57 import pipes as _pipes
58 _shlex.quote = _pipes.quote
63 # Comment out any entries you don't need
73 'hg', # Command line tool
74 #'mercurial', # Python package
76 # Build tools and packaging
78 'virtual-pypi-installer',
82 'nosetests', # Command line tool
83 'nose', # Python package
85 'sqlite3', # Command line tool
86 'sqlite3-python', # Python package
89 'ipython', # Command line tool
90 'IPython', # Python package
91 'argparse', # Useful for utility scripts
105 if _platform.system() == 'win32':
109 class InvalidCheck (KeyError):
110 def __init__(self, check):
111 super(InvalidCheck, self).__init__(check)
118 class DependencyError (Exception):
119 _default_url = 'http://software-carpentry.org/setup/'
120 _setup_urls = { # (system, version, package) glob pairs
121 ('*', '*', 'Cython'): 'http://docs.cython.org/src/quickstart/install.html',
122 ('Linux', '*', 'EasyMercurial'): 'http://easyhg.org/download.html#download-linux',
123 ('Darwin', '*', 'EasyMercurial'): 'http://easyhg.org/download.html#download-mac',
124 ('Windows', '*', 'EasyMercurial'): 'http://easyhg.org/download.html#download-windows',
125 ('*', '*', 'EasyMercurial'): 'http://easyhg.org/download.html',
126 ('*', '*', 'argparse'): 'https://pypi.python.org/pypi/argparse#installation',
127 ('*', '*', 'ash'): 'http://www.in-ulm.de/~mascheck/various/ash/',
128 ('*', '*', 'bash'): 'http://www.gnu.org/software/bash/manual/html_node/Basic-Installation.html#Basic-Installation',
129 ('Linux', '*', 'chromium'): 'http://code.google.com/p/chromium/wiki/LinuxBuildInstructions',
130 ('Darwin', '*', 'chromium'): 'http://code.google.com/p/chromium/wiki/MacBuildInstructions',
131 ('Windows', '*', 'chromium'): 'http://www.chromium.org/developers/how-tos/build-instructions-windows',
132 ('*', '*', 'chromium'): 'http://www.chromium.org/developers/how-tos',
133 ('Windows', '*', 'emacs'): 'http://www.gnu.org/software/emacs/windows/Installing-Emacs.html',
134 ('*', '*', 'emacs'): 'http://www.gnu.org/software/emacs/#Obtaining',
135 ('*', '*', 'firefox'): 'http://www.mozilla.org/en-US/firefox/new/',
136 ('Linux', '*', 'gedit'): 'http://www.linuxfromscratch.org/blfs/view/svn/gnome/gedit.html',
137 ('*', '*', 'git'): 'http://git-scm.com/downloads',
138 ('*', '*', 'google-chrome'): 'https://www.google.com/intl/en/chrome/browser/',
139 ('*', '*', 'hg'): 'http://mercurial.selenic.com/',
140 ('*', '*', 'mercurial'): 'http://mercurial.selenic.com/',
141 ('*', '*', 'IPython'): 'http://ipython.org/install.html',
142 ('*', '*', 'ipython'): 'http://ipython.org/install.html',
143 ('*', '*', 'jinja'): 'http://jinja.pocoo.org/docs/intro/#installation',
144 ('*', '*', 'kate'): 'http://kate-editor.org/get-it/',
145 ('*', '*', 'make'): 'http://www.gnu.org/software/make/',
146 ('Darwin', '*', 'matplotlib'): 'http://matplotlib.org/users/installing.html#building-on-osx',
147 ('Windows', '*', 'matplotlib'): 'http://matplotlib.org/users/installing.html#installing-on-windows',
148 ('*', '*', 'matplotlib'): 'http://matplotlib.org/users/installing.html#installing',
149 ('*', '*', 'mayavi.mlab'): 'http://docs.enthought.com/mayavi/mayavi/installation.html',
150 ('*', '*', 'nano'): 'http://www.nano-editor.org/dist/latest/faq.html#3',
151 ('*', '*', 'networkx'): 'http://networkx.github.com/documentation/latest/install.html#installing',
152 ('*', '*', 'nose'): 'https://nose.readthedocs.org/en/latest/#installation-and-quick-start',
153 ('*', '*', 'nosetests'): 'https://nose.readthedocs.org/en/latest/#installation-and-quick-start',
154 ('*', '*', 'notepad++'): 'http://notepad-plus-plus.org/download/v6.3.html',
155 ('*', '*', 'numpy'): 'http://docs.scipy.org/doc/numpy/user/install.html',
156 ('*', '*', 'pandas'): 'http://pandas.pydata.org/pandas-docs/stable/install.html',
157 ('*', '*', 'pip'): 'http://www.pip-installer.org/en/latest/installing.html',
158 ('*', '*', 'python'): 'http://www.python.org/download/releases/2.7.3/#download',
159 ('*', '*', 'pyzmq'): 'https://github.com/zeromq/pyzmq/wiki/Building-and-Installing-PyZMQ',
160 ('Linux', '*', 'scipy'): 'http://www.scipy.org/Installing_SciPy/Linux',
161 ('Darwin', '*', 'scipy'): 'http://www.scipy.org/Installing_SciPy/Mac_OS_X',
162 ('Windows', '*', 'scipy'): 'http://www.scipy.org/Installing_SciPy/Windows',
163 ('*', '*', 'scipy'): 'http://www.scipy.org/Installing_SciPy',
164 ('*', '*', 'setuptools'): 'https://pypi.python.org/pypi/setuptools#installation-instructions',
165 ('*', '*', 'sqlite3'): 'http://www.sqlite.org/download.html',
166 ('*', '*', 'sublime-text'): 'http://www.sublimetext.com/2',
167 ('*', '*', 'sympy'): 'http://docs.sympy.org/dev/install.html',
168 ('Darwin', '*', 'textmate'): 'http://macromates.com/',
169 ('Darwin', '*', 'textwrangler'): 'http://www.barebones.com/products/textwrangler/download.html',
170 ('*', '*', 'tornado'): 'http://www.tornadoweb.org/',
171 ('*', '*', 'vim'): 'http://www.vim.org/download.php',
172 ('Darwin', '*', 'xcode'): 'https://developer.apple.com/xcode/',
173 ('*', '*', 'xemacs'): 'http://www.us.xemacs.org/Install/',
174 ('*', '*', 'zsh'): 'http://www.zsh.org/',
177 def _get_message(self):
179 def _set_message(self, message):
180 self._message = message
181 message = property(_get_message, _set_message)
183 def __init__(self, checker, message, causes=None):
184 super(DependencyError, self).__init__(message)
185 self.checker = checker
186 self.message = message
192 system = _platform.system()
195 'linux_distribution',
199 value = getattr(_platform, pversion)()
203 package = self.checker.name
204 for (s,v,p),url in self._setup_urls.items():
205 if (_fnmatch.fnmatch(system, s) and
206 _fnmatch.fnmatch(version, v) and
207 _fnmatch.fnmatch(package, p)):
209 return self._default_url
214 'check for {0} failed:'.format(self.checker.full_name()),
216 ' For instructions on installing an up-to-date version, see',
220 lines.append(' causes:')
221 for cause in self.causes:
222 lines.extend(' ' + line for line in str(cause).splitlines())
223 return '\n'.join(lines)
226 def check(checks=None):
233 checker = CHECKER[check]
234 except KeyError as e:
235 raise InvalidCheck(check)# from e
236 _sys.stdout.write('check {0}...\t'.format(checker.full_name()))
238 version = checker.check()
239 except DependencyError as e:
241 _sys.stdout.write('fail\n')
243 _sys.stdout.write('pass\n')
244 successes.append((checker, version))
246 print('\nSuccesses:\n')
247 for checker,version in successes:
248 print('{0} {1}'.format(
250 version or 'unknown'))
254 for failure in failures:
255 if failure not in printed:
258 printed.append(failure)
263 class Dependency (object):
264 def __init__(self, name, long_name=None, minimum_version=None,
265 version_delimiter='.', and_dependencies=None,
266 or_dependencies=None):
268 self.long_name = long_name or name
269 self.minimum_version = minimum_version
270 self.version_delimiter = version_delimiter
271 if not and_dependencies:
272 and_dependencies = []
273 self.and_dependencies = and_dependencies
274 if not or_dependencies:
276 self.or_dependencies = or_dependencies
277 self._check_error = None
280 return '<{0} {1}>'.format(type(self).__name__, self.name)
283 if self.name == self.long_name:
286 return '{0} ({1})'.format(self.long_name, self.name)
289 if self._check_error:
290 raise self._check_error
292 self._check_dependencies()
294 except DependencyError as e:
295 self._check_error = e # cache for future calls
298 def _check_dependencies(self):
299 for dependency in self.and_dependencies:
300 if not hasattr(dependency, 'check'):
301 dependency = CHECKER[dependency]
304 except DependencyError as e:
305 raise DependencyError(
308 'some dependencies for {0} were not satisfied'
309 ).format(self.full_name()),
313 for dependency in self.or_dependencies:
314 if not hasattr(dependency, 'check'):
315 dependency = CHECKER[dependency]
317 version = dependency.check()
318 except DependencyError as e:
322 'dependency': dependency,
325 break # no need to test other dependencies
326 if self.or_dependencies and not self.or_pass:
327 raise DependencyError(
330 '{0} requires at least one of the following dependencies'
331 ).format(self.full_name()),
335 version = self._get_version()
336 parsed_version = None
337 if hasattr(self, '_get_parsed_version'):
338 parsed_version = self._get_parsed_version()
339 if self.minimum_version:
340 self._check_version(version=version, parsed_version=parsed_version)
343 def _get_version(self):
344 raise NotImplementedError(self)
346 def _minimum_version_string(self):
347 return self.version_delimiter.join(
348 str(part) for part in self.minimum_version)
350 def _check_version(self, version, parsed_version=None):
351 if not parsed_version:
352 parsed_version = self._parse_version(version=version)
353 if not parsed_version or parsed_version < self.minimum_version:
354 raise DependencyError(
356 message='outdated version of {0}: {1} (need >= {2})'.format(
357 self.full_name(), version, self._minimum_version_string()))
359 def _parse_version(self, version):
363 for part in version.split(self.version_delimiter):
365 parsed_version.append(int(part))
366 except ValueError as e:
367 raise DependencyError(
370 'unparsable {0!r} in version {1} of {2}, (need >= {3})'
372 part, version, self.full_name(),
373 self._minimum_version_string()))# from e
374 return tuple(parsed_version)
377 class PythonDependency (Dependency):
378 def __init__(self, name='python', long_name='Python version',
379 minimum_version=(2, 6), **kwargs):
380 super(PythonDependency, self).__init__(
381 name=name, long_name=long_name, minimum_version=minimum_version,
384 def _get_version(self):
387 def _get_parsed_version(self):
388 return _sys.version_info
391 CHECKER['python'] = PythonDependency()
394 class CommandDependency (Dependency):
395 exe_extension = _distutils_ccompiler.new_compiler().exe_extension
397 def __init__(self, command, paths=None, version_options=('--version',),
398 stdin=None, version_regexp=None, version_stream='stdout',
400 if 'name' not in kwargs:
401 kwargs['name'] = command
402 super(CommandDependency, self).__init__(**kwargs)
403 self.command = command
405 self.version_options = version_options
407 if not version_regexp:
408 regexp = r'([\d][\d{0}]*[\d])'.format(self.version_delimiter)
409 version_regexp = _re.compile(regexp)
410 self.version_regexp = version_regexp
411 self.version_stream = version_stream
413 def _get_command_version_stream(self, command=None, stdin=None,
416 command = self.command + (self.exe_extension or '')
420 popen_stdin = _subprocess.PIPE
424 p = _subprocess.Popen(
425 [command] + list(self.version_options), stdin=popen_stdin,
426 stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
427 universal_newlines=True)
429 raise DependencyError(
431 message="could not find '{0}' executable".format(command),
433 stdout,stderr = p.communicate(stdin)
435 if status not in expect:
437 "failed to execute: {0} {1}".format(
439 ' '.join(_shlex.quote(arg)
440 for arg in self.version_options)),
441 'status: {0}'.format(status),
443 for name,string in [('stdout', stdout), ('stderr', stderr)]:
445 lines.extend([name + ':', string])
446 raise DependencyError(checker=self, message='\n'.join(lines))
447 for name,string in [('stdout', stdout), ('stderr', stderr)]:
448 if name == self.version_stream:
450 raise DependencyError(
452 message='empty version stream on {0} for {1}'.format(
453 self.version_stream, command))
455 raise NotImplementedError(self.version_stream)
457 def _get_version_stream(self, **kwargs):
458 paths = [self.command + (self.exe_extension or '')]
459 if self.exe_extension:
460 paths.append(self.command) # also look at the extension-less path
462 paths.extend(self.paths)
466 return self._get_command_version_stream(command=path, **kwargs)
467 except DependencyError as e:
469 raise DependencyError(
471 message='errors finding {0} version'.format(
475 def _get_version(self):
476 version_stream = self._get_version_stream()
477 match = self.version_regexp.search(version_stream)
479 raise DependencyError(
481 message='no version string in output:\n{0}'.format(
483 return match.group(1)
486 for command,long_name,minimum_version,paths in [
487 ('sh', 'Bourne Shell', None, None),
488 ('ash', 'Almquist Shell', None, None),
489 ('bash', 'Bourne Again Shell', None, None),
490 ('csh', 'C Shell', None, None),
491 ('ksh', 'KornShell', None, None),
492 ('dash', 'Debian Almquist Shell', None, None),
493 ('tcsh', 'TENEX C Shell', None, None),
494 ('zsh', 'Z Shell', None, None),
495 ('git', 'Git', (1, 7, 0), None),
496 ('hg', 'Mercurial', (2, 0, 0), None),
497 ('EasyMercurial', None, (1, 3), None),
498 ('pip', None, None, None),
499 ('sqlite3', 'SQLite 3', None, None),
500 ('nosetests', 'Nose', (1, 0, 0), None),
501 ('ipython', 'IPython script', (0, 13), None),
502 ('emacs', 'Emacs', None, None),
503 ('xemacs', 'XEmacs', None, None),
504 ('vim', 'Vim', None, None),
505 ('vi', None, None, None),
506 ('nano', 'Nano', None, None),
507 ('gedit', None, None, None),
508 ('kate', 'Kate', None, None),
509 ('notepad++', 'Notepad++', None, [
511 _ROOT_PATH, 'Program Files', 'Notepad++', 'notepad++.exe'),
513 ('firefox', 'Firefox', None, [
515 _ROOT_PATH, 'Program Files', 'Mozilla Firefox', 'firefox.exe'),
517 ('google-chrome', 'Google Chrome', None, [
519 _ROOT_PATH, 'Program Files', 'Google', 'Chrome', 'Application',
522 ('chromium', 'Chromium', None, None),
526 CHECKER[command] = CommandDependency(
527 command=command, paths=paths, long_name=long_name,
528 minimum_version=minimum_version)
529 del command, long_name, minimum_version, paths # cleanup namespace
532 class MakeDependency (CommandDependency):
533 makefile = '\n'.join([
535 '\t@echo "MAKE_VERSION=$(MAKE_VERSION)"',
536 '\t@echo "MAKE=$(MAKE)"',
540 def _get_version(self):
542 return super(MakeDependency, self)._get_version()
543 except DependencyError as e:
544 version_options = self.version_options
545 self.version_options = ['-f', '-']
547 stream = self._get_version_stream(stdin=self.makefile)
549 for line in stream.splitlines():
551 key,value = line.split('=', 1)
552 except ValueError as ve:
553 raise e# from NotImplementedError(stream)
555 if info.get('MAKE_VERSION', None):
556 return info['MAKE_VERSION']
557 elif info.get('MAKE', None):
561 self.version_options = version_options
564 CHECKER['make'] = MakeDependency(command='make', minimum_version=None)
567 class EasyInstallDependency (CommandDependency):
568 def _get_version(self):
570 return super(EasyInstallDependency, self)._get_version()
571 except DependencyError as e:
572 version_stream = self.version_stream
574 self.version_stream = 'stderr'
575 stream = self._get_version_stream(expect=(1,))
576 if 'option --version not recognized' in stream:
577 return 'unknown (possibly Setuptools?)'
579 self.version_stream = version_stream
582 CHECKER['easy_install'] = EasyInstallDependency(
583 command='easy_install', long_name='Setuptools easy_install',
584 minimum_version=None)
587 class PathCommandDependency (CommandDependency):
588 """A command that doesn't support --version or equivalent options
590 On some operating systems (e.g. OS X), a command's executable may
591 be hard to find, or not exist in the PATH. Work around that by
592 just checking for the existence of a characteristic file or
593 directory. Since the characteristic path may depend on OS,
594 installed version, etc., take a list of paths, and succeed if any
597 def _get_command_version_stream(self, *args, **kwargs):
598 raise NotImplementedError()
600 def _get_version_stream(self, *args, **kwargs):
601 raise NotImplementedError()
603 def _get_version(self):
604 for path in self.paths:
605 if _os.path.exists(path):
607 raise DependencyError(
610 'nothing exists at any of the expected paths for {0}:\n {1}'
613 '\n '.join(p for p in self.paths)))
616 for paths,name,long_name in [
617 ([_os.path.join(_ROOT_PATH, 'Applications', 'Sublime Text 2.app')],
618 'sublime-text', 'Sublime Text'),
619 ([_os.path.join(_ROOT_PATH, 'Applications', 'TextMate.app')],
620 'textmate', 'TextMate'),
621 ([_os.path.join(_ROOT_PATH, 'Applications', 'TextWrangler.app')],
622 'textwrangler', 'TextWrangler'),
623 ([_os.path.join(_ROOT_PATH, 'Applications', 'Safari.app')],
625 ([_os.path.join(_ROOT_PATH, 'Applications', 'Xcode.app'), # OS X >=1.7
626 _os.path.join(_ROOT_PATH, 'Developer', 'Applications', 'Xcode.app'
633 CHECKER[name] = PathCommandDependency(
634 command=None, paths=paths, name=name, long_name=long_name)
635 del paths, name, long_name # cleanup namespace
638 class PythonPackageDependency (Dependency):
639 def __init__(self, package, **kwargs):
640 if 'name' not in kwargs:
641 kwargs['name'] = package
642 if 'and_dependencies' not in kwargs:
643 kwargs['and_dependencies'] = []
644 if 'python' not in kwargs['and_dependencies']:
645 kwargs['and_dependencies'].append('python')
646 super(PythonPackageDependency, self).__init__(**kwargs)
647 self.package = package
649 def _get_version(self):
650 package = self._get_package(self.package)
651 return self._get_version_from_package(package)
653 def _get_package(self, package):
655 return _importlib.import_module(package)
656 except ImportError as e:
657 raise DependencyError(
659 message="could not import the '{0}' package for {1}".format(
660 package, self.full_name()),
663 def _get_version_from_package(self, package):
665 version = package.__version__
666 except AttributeError:
671 for package,name,long_name,minimum_version,and_dependencies in [
672 ('nose', None, 'Nose Python package',
673 CHECKER['nosetests'].minimum_version, None),
674 ('jinja2', 'jinja', 'Jinja', (2, 6), None),
675 ('zmq', 'pyzmq', 'PyZMQ', (2, 1, 4), None),
676 ('IPython', None, 'IPython Python package',
677 CHECKER['ipython'].minimum_version, ['jinja', 'tornado', 'pyzmq']),
678 ('argparse', None, 'Argparse', None, None),
679 ('numpy', None, 'NumPy', None, None),
680 ('scipy', None, 'SciPy', None, None),
681 ('matplotlib', None, 'Matplotlib', None, None),
682 ('pandas', None, 'Pandas', (0, 8), None),
683 ('sympy', None, 'SymPy', None, None),
684 ('Cython', None, None, None, None),
685 ('networkx', None, 'NetworkX', None, None),
686 ('mayavi.mlab', None, 'MayaVi', None, None),
687 ('setuptools', None, 'Setuptools', None, None),
695 kwargs['and_dependencies'] = and_dependencies
696 CHECKER[name] = PythonPackageDependency(
697 package=package, name=name, long_name=long_name,
698 minimum_version=minimum_version, **kwargs)
700 del package, name, long_name, minimum_version, and_dependencies, kwargs
703 class MercurialPythonPackage (PythonPackageDependency):
704 def _get_version(self):
705 try: # mercurial >= 1.2
706 package = _importlib.import_module('mercurial.util')
707 except ImportError as e: # mercurial <= 1.1.2
708 package = self._get_package('mercurial.version')
709 return package.get_version()
711 return package.version()
714 CHECKER['mercurial'] = MercurialPythonPackage(
715 package='mercurial.util', name='mercurial',
716 long_name='Mercurial Python package',
717 minimum_version=CHECKER['hg'].minimum_version)
720 class TornadoPythonPackage (PythonPackageDependency):
721 def _get_version_from_package(self, package):
722 return package.version
724 def _get_parsed_version(self):
725 package = self._get_package(self.package)
726 return package.version_info
729 CHECKER['tornado'] = TornadoPythonPackage(
730 package='tornado', name='tornado', long_name='Tornado', minimum_version=(2, 0))
733 class SQLitePythonPackage (PythonPackageDependency):
734 def _get_version_from_package(self, package):
737 def _get_parsed_version(self):
738 return _sys.version_info
741 CHECKER['sqlite3-python'] = SQLitePythonPackage(
742 package='sqlite3', name='sqlite3-python',
743 long_name='SQLite Python package',
744 minimum_version=CHECKER['sqlite3'].minimum_version)
747 class UserTaskDependency (Dependency):
748 "Prompt the user to complete a task and check for success"
749 def __init__(self, prompt, **kwargs):
750 super(UserTaskDependency, self).__init__(**kwargs)
754 if _sys.version_info >= (3, ):
755 result = input(self.prompt)
757 result = raw_input(self.prompt)
758 return self._check_result(result)
760 def _check_result(self, result):
761 raise NotImplementedError()
764 class EditorTaskDependency (UserTaskDependency):
765 def __init__(self, **kwargs):
766 self.path = _os.path.expanduser(_os.path.join(
767 '~', 'swc-installation-test.txt'))
768 self.contents = 'Hello, world!'
769 super(EditorTaskDependency, self).__init__(
771 'Open your favorite text editor and create the file\n'
773 'containing the line:\n'
775 'Press enter here after you have done this.\n'
776 'You may remove the file after you have finished testing.'
777 ).format(self.path, self.contents),
780 def _check_result(self, result):
783 with open(self.path, 'r') as f:
786 raise DependencyError(
788 message='could not open {0!r}: {1}'.format(self.path, e)
790 if contents.strip() != self.contents:
791 raise DependencyError(
794 'file contents ({0!r}) did not match the expected {1!r}'
795 ).format(contents, self.contents))
798 CHECKER['other-editor'] = EditorTaskDependency(
799 name='other-editor', long_name='')
802 class VirtualDependency (Dependency):
804 return '{0} {1}'.format(
805 self.or_pass['dependency'].full_name(),
806 self.or_pass['version'])
809 for name,long_name,dependencies in [
810 ('virtual-shell', 'command line shell', (
820 ('virtual-editor', 'text/code editor', (
832 'other-editor', # last because it requires user interaction
834 ('virtual-browser', 'web browser', (
840 ('virtual-pypi-installer', 'PyPI installer', (
845 CHECKER[name] = VirtualDependency(
846 name=name, long_name=long_name, or_dependencies=dependencies)
847 del name, long_name, dependencies # cleanup namespace
850 def _print_info(key, value, indent=19):
851 print('{0}{1}: {2}'.format(key, ' '*(indent-len(key)), value))
853 def print_system_info():
854 print("If you do not understand why the above failures occurred,")
855 print("copy and send the *entire* output (all info above and summary")
856 print("below) to the instructor for help.")
858 print('==================')
859 print('System information')
860 print('==================')
861 _print_info('os.name', _os.name)
862 _print_info('os.uname', _platform.uname())
863 _print_info('platform', _sys.platform)
864 _print_info('platform+', _platform.platform())
866 'linux_distribution',
870 value = getattr(_platform, pversion)()
872 _print_info(pversion, value)
873 _print_info('prefix', _sys.prefix)
874 _print_info('exec_prefix', _sys.exec_prefix)
875 _print_info('executable', _sys.executable)
876 _print_info('version_info', _sys.version_info)
877 _print_info('version', _sys.version)
878 _print_info('environment', '')
879 for key,value in sorted(_os.environ.items()):
880 print(' {0}={1}'.format(key, value))
881 print('==================')
883 def print_suggestions(instructor_fallback=True):
885 print('For suggestions on installing missing packages, see')
886 print('http://software-carpentry.org/setup/')
888 print('For instructings on installing a particular package,')
889 print('see the failure message for that package printed above.')
890 if instructor_fallback:
892 print('For help, email the *entire* output of this script to')
893 print('your instructor.')
896 if __name__ == '__main__':
897 import optparse as _optparse
899 parser = _optparse.OptionParser(usage='%prog [options] [check...]')
901 parser.format_epilog = lambda formatter: '\n' + epilog
903 '-v', '--verbose', action='store_true',
904 help=('print additional information to help troubleshoot '
905 'installation issues'))
906 options,args = parser.parse_args()
909 except InvalidCheck as e:
910 print("I don't know how to check for {0!r}".format(e.check))
911 print('I do know how to check for:')
912 for key,checker in sorted(CHECKER.items()):
913 if checker.long_name != checker.name:
914 print(' {0} {1}({2})'.format(
915 key, ' '*(20-len(key)), checker.long_name))
917 print(' {0}'.format(key))
923 print_suggestions(instructor_fallback=True)