From: W. Trevor King Date: Sun, 27 Jan 2013 19:33:46 +0000 (-0500) Subject: swc-installation-test-2.py: Print full DependencyError chain X-Git-Url: http://git.tremily.us/?p=swc-setup-installation-test.git;a=commitdiff_plain;h=1be065924ee0fa9a92abba0647f27f3134e9d590 swc-installation-test-2.py: Print full DependencyError chain If a requirement is not satisfied due to an and_dependency or or_dependency failure, raise a new DependencyError and attach the original error as its cause (this would be easier if we didn't have to preserve Python 2.x support). This way we can print the whole chain (e.g. virtual-shell failed because sh is not installed), instead of just the lowest level error. Also indent the messages, because: check for virtual-editor failed: or-dependency not satisfied for virtual-editor For instructions on installing an up-to-date version, see http://software-carpentry.org/setup/ cause: check for Notepad++ (notepad++) failed: could not find 'notepad++' executable For instructions on installing an up-to-date version, see http://software-carpentry.org/setup/ is more readable than: check for virtual-editor failed: or-dependency not satisfied for virtual-editor For instructions on installing an up-to-date version, see http://software-carpentry.org/setup/ cause: check for Notepad++ (notepad++) failed: could not find 'notepad++' executable For instructions on installing an up-to-date version, see http://software-carpentry.org/setup/ --- diff --git a/setup/swc-installation-test-2.py b/setup/swc-installation-test-2.py index 4cd22e2..35e3d5c 100755 --- a/setup/swc-installation-test-2.py +++ b/setup/swc-installation-test-2.py @@ -110,17 +110,24 @@ class DependencyError (Exception): self._message = message message = property(_get_message, _set_message) - def __init__(self, checker, message): + def __init__(self, checker, message, cause=None): super(DependencyError, self).__init__(message) self.checker = checker self.message = message + self.cause = cause def __str__(self): url = 'http://software-carpentry.org/setup/' # TODO: per-package URL - return 'check for {0} failed:\n{1}\n{2}\n{3}'.format( - self.checker.full_name(), self.message, - 'For instructions on installing an up-to-date version, see', - url) + lines = [ + 'check for {0} failed:'.format(self.checker.full_name()), + ' ' + self.message, + ' For instructions on installing an up-to-date version, see', + ' ' + url, + ] + if self.cause: + lines.append(' cause:') + lines.extend(' ' + line for line in str(self.cause).splitlines()) + return '\n'.join(lines) def check(checks=None): @@ -199,7 +206,14 @@ class Dependency (object): for dependency in self.and_dependencies: if not hasattr(dependency, 'check'): dependency = CHECKER[dependency] - dependency.check() + try: + dependency.check() + except DependencyError as e: + raise DependencyError( + checker=self, + message='and-dependency not satisfied for {0}'.format( + self.full_name()), + cause=e) self.or_pass = or_error = None for dependency in self.or_dependencies: if not hasattr(dependency, 'check'): @@ -215,7 +229,11 @@ class Dependency (object): } break # no need to test other dependencies if self.or_dependencies and not self.or_pass: - raise or_error + raise DependencyError( + checker=self, + message='or-dependency not satisfied for {0}'.format( + self.full_name()), + cause=or_error) def _check(self): version = self._get_version()