Hello community, here is the log from the commit of package python-Fabric for openSUSE:Factory checked in at 2016-03-02 14:21:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Fabric (Old) and /work/SRC/openSUSE:Factory/.python-Fabric.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Fabric" Changes: -------- --- /work/SRC/openSUSE:Factory/python-Fabric/python-Fabric.changes 2015-05-07 09:22:36.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-Fabric.new/python-Fabric.changes 2016-03-02 14:21:30.000000000 +0100 @@ -1,0 +2,18 @@ +Thu Feb 18 15:32:02 UTC 2016 - [email protected] + +- update to version 1.10.2: + * Fix issue with ssh/config not having a cross-platform default path. + * Recursively unwrap decorators instead of only unwrapping a single + decorator level, when obtaining task docstrings. + * Fix “NameError: free variable referenced before assignment in + enclosing scope”. + * Redirect output of cd to /dev/null so users enabling bash’s + CDPATH (or similar features in other shells) don’t have polluted + output captures. + * Fix a couple minor issues with the operation of & demo code for + the JobQueue class. + * Update functionality added in #1213 so abort error messages don’t + get printed twice (once by us, once by sys.exit) but the annotated + exception error message is retained. + +------------------------------------------------------------------- Old: ---- Fabric-1.10.1.tar.gz New: ---- Fabric-1.10.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Fabric.spec ++++++ --- /var/tmp/diff_new_pack.oHf39d/_old 2016-03-02 14:21:31.000000000 +0100 +++ /var/tmp/diff_new_pack.oHf39d/_new 2016-03-02 14:21:31.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-Fabric # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,31 +16,31 @@ # +%if 0%{?suse_version} && 0%{?suse_version} <= 1110 +%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} +%else +BuildArch: noarch +%endif Name: python-Fabric -Version: 1.10.1 +Version: 1.10.2 Release: 0 Summary: Fabric is a simple, Pythonic tool for remote execution and deployment License: BSD-2-Clause Group: Development/Languages/Python Url: http://fabfile.org Source: https://pypi.python.org/packages/source/F/Fabric/Fabric-%{version}.tar.gz -BuildRequires: python-devel -BuildRequires: python-setuptools # Test requirements: #TODO: Disabled due to errors / fudge requirement #BuildRequires: python-fudge #BuildRequires: python-nose # Documentation requirements: BuildRequires: python-Sphinx +BuildRequires: python-devel BuildRequires: python-paramiko >= 1.10 +BuildRequires: python-setuptools Requires: python-paramiko >= 1.10 Requires: python-setuptools BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else -BuildArch: noarch -%endif %description Fabric is a Python (2.5 or higher) library and command-line tool for ++++++ Fabric-1.10.1.tar.gz -> Fabric-1.10.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/Fabric.egg-info/PKG-INFO new/Fabric-1.10.2/Fabric.egg-info/PKG-INFO --- old/Fabric-1.10.1/Fabric.egg-info/PKG-INFO 2014-12-20 00:19:18.000000000 +0100 +++ new/Fabric-1.10.2/Fabric.egg-info/PKG-INFO 2015-06-19 20:18:45.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: Fabric -Version: 1.10.1 +Version: 1.10.2 Summary: Fabric is a simple, Pythonic tool for remote execution and deployment. Home-page: http://fabfile.org Author: Jeff Forcier @@ -24,27 +24,29 @@ commands (normally or via ``sudo``) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution. - + Typical use involves creating a Python module containing one or more functions, then executing them via the ``fab`` command-line tool. Below is a small but - complete "fabfile" containing a single task:: + complete "fabfile" containing a single task: + + .. code-block:: python - from fabric.api import run + from fabric.api import run - def host_type(): - run('uname -s') + def host_type(): + run('uname -s') Once a task is defined, it may be run on one or more servers, like so:: - $ fab -H localhost,linuxbox host_type - [localhost] run: uname -s - [localhost] out: Darwin - [linuxbox] run: uname -s - [linuxbox] out: Linux - - Done. - Disconnecting from localhost... done. - Disconnecting from linuxbox... done. + $ fab -H localhost,linuxbox host_type + [localhost] run: uname -s + [localhost] out: Darwin + [linuxbox] run: uname -s + [linuxbox] out: Linux + + Done. + Disconnecting from localhost... done. + Disconnecting from linuxbox... done. In addition to use via the ``fab`` tool, Fabric's components may be imported into other Python code, providing a Pythonic interface to the SSH protocol diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/Fabric.egg-info/SOURCES.txt new/Fabric-1.10.2/Fabric.egg-info/SOURCES.txt --- old/Fabric-1.10.1/Fabric.egg-info/SOURCES.txt 2014-12-20 00:19:18.000000000 +0100 +++ new/Fabric-1.10.2/Fabric.egg-info/SOURCES.txt 2015-06-19 20:18:45.000000000 +0200 @@ -12,8 +12,6 @@ Fabric.egg-info/requires.txt Fabric.egg-info/top_level.txt fabfile/__init__.py -fabfile/tag.py -fabfile/utils.py fabric/__init__.py fabric/__main__.py fabric/api.py @@ -44,6 +42,7 @@ sites/_shared_static/logo.png sites/docs/conf.py sites/docs/index.rst +sites/docs/running_tests.rst sites/docs/tutorial.rst sites/docs/api/contrib/console.rst sites/docs/api/contrib/django.rst @@ -67,6 +66,7 @@ sites/docs/usage/parallel.rst sites/docs/usage/ssh.rst sites/docs/usage/tasks.rst +sites/www/.changelog.rst.swp sites/www/changelog.rst sites/www/conf.py sites/www/contact.rst @@ -99,6 +99,7 @@ tests/test_version.py tests/utils.py tests/support/__init__.py +tests/support/aborts.py tests/support/classbased_task_fabfile.py tests/support/decorated_fabfile.py tests/support/decorated_fabfile_with_classbased_task.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/Fabric.egg-info/requires.txt new/Fabric-1.10.2/Fabric.egg-info/requires.txt --- old/Fabric-1.10.1/Fabric.egg-info/requires.txt 2014-12-20 00:19:18.000000000 +0100 +++ new/Fabric-1.10.2/Fabric.egg-info/requires.txt 2015-06-19 20:18:45.000000000 +0200 @@ -1 +1 @@ -paramiko>=1.10,<1.13 \ No newline at end of file +paramiko>=1.10 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/LICENSE new/Fabric-1.10.2/LICENSE --- old/Fabric-1.10.1/LICENSE 2014-09-19 05:11:49.000000000 +0200 +++ new/Fabric-1.10.2/LICENSE 2015-04-30 04:32:40.000000000 +0200 @@ -1,4 +1,4 @@ -Copyright (c) 2009-2014 Jeffrey E. Forcier +Copyright (c) 2009-2015 Jeffrey E. Forcier Copyright (c) 2008-2009 Christian Vest Hansen All rights reserved. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/PKG-INFO new/Fabric-1.10.2/PKG-INFO --- old/Fabric-1.10.1/PKG-INFO 2014-12-20 00:19:18.000000000 +0100 +++ new/Fabric-1.10.2/PKG-INFO 2015-06-19 20:18:45.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: Fabric -Version: 1.10.1 +Version: 1.10.2 Summary: Fabric is a simple, Pythonic tool for remote execution and deployment. Home-page: http://fabfile.org Author: Jeff Forcier @@ -24,27 +24,29 @@ commands (normally or via ``sudo``) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution. - + Typical use involves creating a Python module containing one or more functions, then executing them via the ``fab`` command-line tool. Below is a small but - complete "fabfile" containing a single task:: + complete "fabfile" containing a single task: + + .. code-block:: python - from fabric.api import run + from fabric.api import run - def host_type(): - run('uname -s') + def host_type(): + run('uname -s') Once a task is defined, it may be run on one or more servers, like so:: - $ fab -H localhost,linuxbox host_type - [localhost] run: uname -s - [localhost] out: Darwin - [linuxbox] run: uname -s - [linuxbox] out: Linux - - Done. - Disconnecting from localhost... done. - Disconnecting from linuxbox... done. + $ fab -H localhost,linuxbox host_type + [localhost] run: uname -s + [localhost] out: Darwin + [linuxbox] run: uname -s + [linuxbox] out: Linux + + Done. + Disconnecting from localhost... done. + Disconnecting from linuxbox... done. In addition to use via the ``fab`` tool, Fabric's components may be imported into other Python code, providing a Pythonic interface to the SSH protocol diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/README.rst new/Fabric-1.10.2/README.rst --- old/Fabric-1.10.1/README.rst 2014-09-19 04:01:17.000000000 +0200 +++ new/Fabric-1.10.2/README.rst 2015-04-30 04:32:40.000000000 +0200 @@ -9,7 +9,9 @@ Typical use involves creating a Python module containing one or more functions, then executing them via the ``fab`` command-line tool. Below is a small but -complete "fabfile" containing a single task:: +complete "fabfile" containing a single task: + +.. code-block:: python from fabric.api import run diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabfile/__init__.py new/Fabric-1.10.2/fabfile/__init__.py --- old/Fabric-1.10.1/fabfile/__init__.py 2014-09-19 04:01:17.000000000 +0200 +++ new/Fabric-1.10.2/fabfile/__init__.py 2015-05-04 03:23:07.000000000 +0200 @@ -8,9 +8,6 @@ from fabric.api import abort, local, task -import tag -from utils import msg - @task(default=True) def test(args=None): @@ -25,21 +22,3 @@ default_args = "-sv --with-doctest --nologcapture --with-color %s" % tests default_args += (" " + args) if args else "" nose.core.run_exit(argv=[''] + default_args.split()) - - -@task -def upload(): - """ - Build, register and upload to PyPI - """ - with msg("Uploading to PyPI"): - local('python setup.py sdist register upload') - - -@task -def release(force='no'): - """ - Tag, push tag to Github, & upload new version to PyPI. - """ - tag.tag(force=force, push='yes') - upload() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabfile/tag.py new/Fabric-1.10.2/fabfile/tag.py --- old/Fabric-1.10.1/fabfile/tag.py 2014-08-14 22:54:23.000000000 +0200 +++ new/Fabric-1.10.2/fabfile/tag.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,119 +0,0 @@ -from __future__ import with_statement - -from contextlib import nested - -from fabric.api import abort, hide, local, settings, task - -# Need to import this as fabric.version for reload() purposes -import fabric.version -# But nothing is stopping us from making a convenient binding! -_version = fabric.version.get_version - -from utils import msg - - -def _seek_version(cmd, txt): - with nested(hide('running'), msg(txt)): - cmd = cmd % _version('short') - return local(cmd, capture=True) - - -def current_version_is_tagged(): - return _seek_version( - 'git tag | egrep "^%s$"', - "Searching for existing tag" - ) - - -def current_version_is_changelogged(filename): - return _seek_version( - 'egrep "^\* :release:\`%%s " %s' % filename, - "Looking for changelog entry" - ) - - -def update_code(filename, force): - """ - Update version data structure in-code and commit that change to git. - - Normally, if the version file has not been modified, we abort assuming the - user quit without saving. Specify ``force=yes`` to override this. - """ - raw_input("Version update in %r required! Press Enter to load $EDITOR." % filename) - with hide('running'): - local("$EDITOR %s" % filename) - # Try to detect whether user bailed out of the edit - with hide('running'): - has_diff = local("git diff -- %s" % filename, capture=True) - if not has_diff and not force: - abort("You seem to have aborted the file edit, so I'm aborting too.") - return filename - - -def commits_since_last_tag(): - """ - Has any work been done since the last tag? - """ - with hide('running'): - return local("git log %s.." % _version('short'), capture=True) - - -@task(default=True) -def tag(force='no', push='no'): - """ - Tag a new release. - - Normally, if a Git tag exists matching the current version, and no Git - commits appear after that tag, we abort assuming the user is making a - mistake or forgot to commit their work. - - To override this -- i.e. to re-tag and re-upload -- specify ``force=yes``. - We assume you know what you're doing if you use this. - - By default we do not push the tag remotely; specify ``push=yes`` to force a - ``git push origin <tag>``. - """ - force = force.lower() in ['y', 'yes'] - with settings(warn_only=True): - changed = [] - # Does the current in-code version exist as a Git tag already? - # If so, this means we haven't updated the in-code version specifier - # yet, and need to do so. - if current_version_is_tagged(): - # That is, if any work has been done since. Sanity check! - if not commits_since_last_tag() and not force: - abort("No work done since last tag!") - # Open editor, update version - version_file = "fabric/version.py" - changed.append(update_code(version_file, force)) - # If the tag doesn't exist, the user has already updated version info - # and we can just move on. - else: - print("Version has already been updated, no need to edit...") - # Similar process but for the changelog. - changelog = "docs/changelog.rst" - if not current_version_is_changelogged(changelog): - changed.append(update_code(changelog, force)) - else: - print("Changelog already updated, no need to edit...") - # Commit any changes - if changed: - with msg("Committing updated version and/or changelog"): - reload(fabric.version) - local("git add %s" % " ".join(changed)) - local("git commit -m \"Cut %s\"" % _version('verbose')) - local("git push") - - # At this point, we've incremented the in-code version and just need to - # tag it in Git. - f = 'f' if force else '' - with msg("Tagging"): - local("git tag -%sam \"Fabric %s\" %s" % ( - f, - _version('normal'), - _version('short') - )) - # And push to the central server, if we were told to - if push.lower() in ['y', 'yes']: - with msg("Pushing"): - local("git push origin %s" % _version('short')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabfile/utils.py new/Fabric-1.10.2/fabfile/utils.py --- old/Fabric-1.10.1/fabfile/utils.py 2014-08-14 22:54:23.000000000 +0200 +++ new/Fabric-1.10.2/fabfile/utils.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -from __future__ import with_statement - -from contextlib import contextmanager - -from fabric.api import hide, puts - - -@contextmanager -def msg(txt): - puts(txt + "...", end='', flush=True) - with hide('everything'): - yield - puts("done.", show_prefix=False, flush=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/context_managers.py new/Fabric-1.10.2/fabric/context_managers.py --- old/Fabric-1.10.1/fabric/context_managers.py 2014-12-19 23:04:26.000000000 +0100 +++ new/Fabric-1.10.2/fabric/context_managers.py 2015-04-30 04:32:40.000000000 +0200 @@ -34,7 +34,6 @@ """ from contextlib import contextmanager, nested -import sys import socket import select @@ -52,9 +51,9 @@ """ Refactored subroutine used by ``hide`` and ``show``. """ + previous = {} try: # Preserve original values, pull in new given value to use - previous = {} for group in output.expand_aliases(groups): previous[group] = output[group] output[group] = which @@ -542,7 +541,7 @@ sock.connect((local_host, local_port)) except Exception, e: print "[%s] rtunnel: cannot connect to %s:%d (from local)" % (env.host_string, local_host, local_port) - chan.close() + channel.close() return print "[%s] rtunnel: opened reverse tunnel: %r -> %r -> %r"\ @@ -566,7 +565,6 @@ transport.cancel_port_forward(remote_bind_address, remote_port) - quiet = lambda: settings(hide('everything'), warn_only=True) quiet.__doc__ = """ Alias to ``settings(hide('everything'), warn_only=True)``. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/contrib/project.py new/Fabric-1.10.2/fabric/contrib/project.py --- old/Fabric-1.10.1/fabric/contrib/project.py 2014-09-19 05:11:49.000000000 +0200 +++ new/Fabric-1.10.2/fabric/contrib/project.py 2015-05-04 02:23:37.000000000 +0200 @@ -52,7 +52,7 @@ * If ``local_dir`` ends with a trailing slash, the files will be dropped inside of ``remote_dir``. E.g. - ``rsync_project("/home/username/project", "foldername/")`` will drop + ``rsync_project("/home/username/project/", "foldername/")`` will drop the contents of ``foldername`` inside of ``/home/username/project``. * If ``local_dir`` does **not** end with a trailing slash (and this includes the default scenario, when ``local_dir`` is not specified), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/job_queue.py new/Fabric-1.10.2/fabric/job_queue.py --- old/Fabric-1.10.1/fabric/job_queue.py 2014-08-14 22:54:23.000000000 +0200 +++ new/Fabric-1.10.2/fabric/job_queue.py 2015-05-04 02:23:37.000000000 +0200 @@ -8,6 +8,7 @@ from __future__ import with_statement import time import Queue +from multiprocessing import Process from fabric.state import env from fabric.network import ssh @@ -175,7 +176,8 @@ # Attach exit codes now that we're all done & have joined all jobs for job in self._completed: - results[job.name]['exit_code'] = job.exitcode + if isinstance(job, Process): + results[job.name]['exit_code'] = job.exitcode return results @@ -213,7 +215,8 @@ from threading import Thread as Bucket # Make a job_queue with a bubble of len 5, and have it print verbosely - jobs = JobQueue(5) + queue = Queue.Queue() + jobs = JobQueue(5, queue) jobs._debug = True # Add 20 procs onto the stack diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/network.py new/Fabric-1.10.2/fabric/network.py --- old/Fabric-1.10.1/fabric/network.py 2014-09-19 05:11:49.000000000 +0200 +++ new/Fabric-1.10.2/fabric/network.py 2015-05-04 02:23:37.000000000 +0200 @@ -532,6 +532,8 @@ # Update env.password, env.passwords if empty set_password(user, host, port, password) # Ctrl-D / Ctrl-C for exit + # TODO: this may no longer actually serve its original purpose and may + # also hide TypeErrors from paramiko. Double check in v2. except (EOFError, TypeError): # Print a newline (in case user was sitting at prompt) print('') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/operations.py new/Fabric-1.10.2/fabric/operations.py --- old/Fabric-1.10.1/fabric/operations.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/fabric/operations.py 2015-06-19 20:16:26.000000000 +0200 @@ -295,7 +295,8 @@ scripts). To do this, specify ``mirror_local_mode=True``. Alternately, you may use the ``mode`` kwarg to specify an exact mode, in - the same vein as ``os.chmod`` or the Unix ``chmod`` command. + the same vein as ``os.chmod``, such as an exact octal number (``0755``) or + a string representing one (``"0755"``). `~fabric.operations.put` will honor `~fabric.context_managers.cd`, so relative values in ``remote_path`` will be prepended by the current remote @@ -663,8 +664,9 @@ # Also place it at the front of the list, in case user is expecting another # prefixed command to be "in" the current working directory. cwd = env.cwd if which == 'remote' else env.lcwd + redirect = " >/dev/null" if not win32 else '' if cwd: - prefixes.insert(0, 'cd %s' % cwd) + prefixes.insert(0, 'cd %s%s' % (cwd, redirect)) glue = " && " prefix = (glue.join(prefixes) + glue) if prefixes else "" return prefix + command diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/sftp.py new/Fabric-1.10.2/fabric/sftp.py --- old/Fabric-1.10.1/fabric/sftp.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/fabric/sftp.py 2015-05-04 02:23:37.000000000 +0200 @@ -12,6 +12,9 @@ from fabric.context_managers import settings +# TODO: use self.sftp.listdir_iter on Paramiko 1.15+ + + def _format_local(local_path, local_is_path): """Format a path for log output""" if local_is_path: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/state.py new/Fabric-1.10.2/fabric/state.py --- old/Fabric-1.10.1/fabric/state.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/fabric/state.py 2015-05-04 02:23:37.000000000 +0200 @@ -68,7 +68,7 @@ return expanded_rc_path default_port = '22' # hurr durr -default_ssh_config_path = '~/.ssh/config' +default_ssh_config_path = os.path.join(os.path.expanduser('~'), '.ssh', 'config') # Options/settings which exist both as environment keys and which can be set on # the command line, are defined here. When used via `fab` they will be added to @@ -426,10 +426,11 @@ 'running': True, 'stdout': True, 'stderr': True, + 'exceptions': False, 'debug': False, 'user': True }, aliases={ - 'everything': ['warnings', 'running', 'user', 'output'], + 'everything': ['warnings', 'running', 'user', 'output', 'exceptions'], 'output': ['stdout', 'stderr'], 'commands': ['stdout', 'running'] }) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/tasks.py new/Fabric-1.10.2/fabric/tasks.py --- old/Fabric-1.10.1/fabric/tasks.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/fabric/tasks.py 2015-05-04 02:23:37.000000000 +0200 @@ -177,7 +177,10 @@ return getattr(self.wrapped, k) def __details__(self): - return get_task_details(self.wrapped) + orig = self + while 'wrapped' in orig.__dict__: + orig = orig.__dict__.get('wrapped') + return get_task_details(orig) def requires_parallel(task): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/utils.py new/Fabric-1.10.2/fabric/utils.py --- old/Fabric-1.10.1/fabric/utils.py 2014-12-19 23:11:58.000000000 +0100 +++ new/Fabric-1.10.2/fabric/utils.py 2015-05-22 01:47:32.000000000 +0200 @@ -30,9 +30,12 @@ """ Abort execution, print ``msg`` to stderr and exit with error status (1.) - This function currently makes use of `sys.exit`_, which raises - `SystemExit`_. Therefore, it's possible to detect and recover from inner - calls to `abort` by using ``except SystemExit`` or similar. + This function currently makes use of `SystemExit`_ in a manner that is + similar to `sys.exit`_ (but which skips the automatic printing to stderr, + allowing us to more tightly control it via settings). + + Therefore, it's possible to detect and recover from inner calls to `abort` + by using ``except SystemExit`` or similar. .. _sys.exit: http://docs.python.org/library/sys.html#sys.exit .. _SystemExit: http://docs.python.org/library/exceptions.html#exceptions.SystemExit @@ -50,7 +53,13 @@ if env.abort_exception: raise env.abort_exception(msg) else: - sys.exit(msg) + # See issue #1318 for details on the below; it lets us construct a + # valid, useful SystemExit while sidestepping the automatic stderr + # print (which would otherwise duplicate with the above in a + # non-controllable fashion). + e = SystemExit(1) + e.message = msg + raise e def warn(msg): @@ -325,9 +334,11 @@ import fabric.state if func is None: func = fabric.state.env.warn_only and warn or abort - # If debug printing is on, append a traceback to the message - if fabric.state.output.debug: - message += "\n\n" + format_exc() + # If exception printing is on, append a traceback to the message + if fabric.state.output.exceptions or fabric.state.output.debug: + exception_message = format_exc() + if exception_message: + message += "\n\n" + exception_message # Otherwise, if we were given an exception, append its contents. elif exception is not None: # Figure out how to get a string out of the exception; EnvironmentError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/fabric/version.py new/Fabric-1.10.2/fabric/version.py --- old/Fabric-1.10.1/fabric/version.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/fabric/version.py 2015-05-04 02:24:14.000000000 +0200 @@ -9,7 +9,7 @@ from os.path import abspath, dirname -VERSION = (1, 10, 1, 'final', 0) +VERSION = (1, 10, 2, 'final', 0) def git_sha(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/docs/index.rst new/Fabric-1.10.2/sites/docs/index.rst --- old/Fabric-1.10.1/sites/docs/index.rst 2014-09-19 04:01:17.000000000 +0200 +++ new/Fabric-1.10.2/sites/docs/index.rst 2015-05-04 02:24:16.000000000 +0200 @@ -76,3 +76,14 @@ :glob: api/contrib/* + + +Contributing & Running Tests +---------------------------- + +For advanced users & developers looking to help fix bugs or add new features. + +.. toctree:: + :hidden: + + running_tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/docs/running_tests.rst new/Fabric-1.10.2/sites/docs/running_tests.rst --- old/Fabric-1.10.1/sites/docs/running_tests.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/Fabric-1.10.2/sites/docs/running_tests.rst 2015-05-04 02:24:16.000000000 +0200 @@ -0,0 +1,48 @@ +====================== +Running Fabric's Tests +====================== + +Fabric is maintained with 100% passing tests. Where possible, patches should +include tests covering the changes, making things far easier to verify & merge. + +When developing on Fabric, it works best to establish a `virtualenv`_ to install +the dependencies in isolation for running tests. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + +.. _first-time-setup: + +First-time Setup +================ + +* Fork the `repository`_ on GitHub +* Clone your new fork (e.g. + ``git clone [email protected]:<your_username>/fabric.git``) +* ``cd fabric`` +* ``virtualenv env`` +* ``. env/bin/activate`` +* ``pip install -r requirements.txt`` +* ``python setup.py develop`` + +.. _`repository`: https://github.com/fabric/fabric + +.. _running-tests: + +Running Tests +============= + +Once your virtualenv is activated (``. env/bin/activate``) & you have the latest +requirements, running tests is just:: + + nosetests tests/ + +You should **always** run tests on ``master`` (or the release branch you're +working with) to ensure they're passing before working on your own +changes/tests. + +Alternatively, if you've run ``python setup.py develop`` on your Fabric clone, +you can also run:: + + fab test + +This adds additional flags which enable running doctests & adds nice coloration. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/docs/usage/env.rst new/Fabric-1.10.2/sites/docs/usage/env.rst --- old/Fabric-1.10.1/sites/docs/usage/env.rst 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/sites/docs/usage/env.rst 2015-05-04 02:23:37.000000000 +0200 @@ -406,7 +406,7 @@ **Default:** ``0`` (i.e. no keepalive) An integer specifying an SSH keepalive interval to use; basically maps to the -SSH config option ``ClientAliveInterval``. Useful if you find connections are +SSH config option ``ServerAliveInterval``. Useful if you find connections are timing out due to meddlesome network hardware or what have you. .. seealso:: :option:`--keepalive` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/docs/usage/output_controls.rst new/Fabric-1.10.2/sites/docs/usage/output_controls.rst --- old/Fabric-1.10.1/sites/docs/usage/output_controls.rst 2014-09-19 04:01:17.000000000 +0200 +++ new/Fabric-1.10.2/sites/docs/usage/output_controls.rst 2015-05-04 02:23:37.000000000 +0200 @@ -19,7 +19,7 @@ .. note:: - All levels, save for ``debug``, are on by default. + All levels, save for ``debug`` and ``exceptions``, are on by default. Standard output levels ---------------------- @@ -52,7 +52,7 @@ * **user**: User-generated output, i.e. local output printed by fabfile code via use of the `~fabric.utils.fastprint` or `~fabric.utils.puts` functions. - + .. versionchanged:: 0.9.2 Added "Executing task" lines to the ``running`` output level. @@ -62,8 +62,10 @@ Debug output ------------ -There is a final atomic output level, ``debug``, which behaves slightly -differently from the rest: +There are two more atomic output levels for use when troubleshooting: +``debug``, which behaves slightly differently from the rest, and +``exceptions``, whose behavior is included in ``debug`` but may be enabled +separately. * **debug**: Turn on debugging (which is off by default.) Currently, this is largely used to view the "full" commands being run; take for example this @@ -82,7 +84,7 @@ [hostname] run: /bin/bash -l -c "ls \"/home/username/Folder Name With Spaces\"" Enabling ``debug`` output will also display full Python tracebacks during - aborts. + aborts (as if ``exceptions`` output was enabled). .. note:: @@ -92,9 +94,16 @@ ``running`` is False but ``debug`` is True, you will still be shown the 'running' line in its debugging form. +* **exceptions**: Enables display of tracebacks when exceptions occur; intended + for use when ``debug`` is set to ``False`` but one is still interested in + detailed error info. + .. versionchanged:: 1.0 Debug output now includes full Python tracebacks during aborts. +.. versionchanged:: 1.11 + Added the ``exceptions`` output level. + .. _output-aliases: Output level aliases Files old/Fabric-1.10.1/sites/www/.changelog.rst.swp and new/Fabric-1.10.2/sites/www/.changelog.rst.swp differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/www/changelog.rst new/Fabric-1.10.2/sites/www/changelog.rst --- old/Fabric-1.10.1/sites/www/changelog.rst 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/sites/www/changelog.rst 2015-06-19 20:18:15.000000000 +0200 @@ -2,6 +2,33 @@ Changelog ========= +* :release:`1.10.2 <2015-06-19>` +* :support:`1325` Clarify `~fabric.operations.put` docs re: the ``mode`` + argument. Thanks to ``@mjmare`` for the catch. +* :bug:`1318` Update functionality added in :issue:`1213` so abort error + messages don't get printed twice (once by us, once by ``sys.exit``) but the + annotated exception error message is retained. Thanks to Felix Almeida for + the report. +* :bug:`1305` (also :issue:`1313`) Fix a couple minor issues with the operation + of & demo code for the ``JobQueue`` class. Thanks to ``@dioh`` and Horst + Gutmann for the report & Cameron Lane for the patch. +* :bug:`980` (also :issue:`1312`) Redirect output of ``cd`` to ``/dev/null`` so + users enabling bash's ``CDPATH`` (or similar features in other shells) don't + have polluted output captures. Thanks to Alex North-Keys for the original + report & Steve Ivy for the fix. +* :bug:`1289` Fix "NameError: free variable referenced before assignment in + enclosing scope". Thanks to ``@SamuelMarks`` for catch & patch. +* :bug:`1286` (also :issue:`971`, :issue:`1032`) Recursively unwrap decorators + instead of only unwrapping a single decorator level, when obtaining task + docstrings. Thanks to Avishai Ish-Shalom for the original report & Max Kovgan + for the patch. +* :bug:`1273` Fix issue with ssh/config not having a cross-platform default + path. Thanks to ``@SamuelMarks`` for catch & patch. +* :feature:`1200` Introduced ``exceptions`` output level, so users don't have to + deal with the debug output just to see tracebacks. +* :support:`1239` Update README to work better under raw docutils so the + example code block is highlighted as Python on PyPI (and not just on our + Sphinx-driven website). Thanks to Marc Abramowitz. * :release:`1.10.1 <2014-12-19>` * :release:`1.9.2 <2014-12-19>` * :bug:`1201` Don't naively glob all `~fabric.operations.get` targets - only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/www/installing.rst new/Fabric-1.10.2/sites/www/installing.rst --- old/Fabric-1.10.1/sites/www/installing.rst 2014-09-19 05:11:49.000000000 +0200 +++ new/Fabric-1.10.2/sites/www/installing.rst 2015-05-04 02:23:37.000000000 +0200 @@ -56,7 +56,7 @@ Python ------ -Fabric requires `Python <http://python.org>`_ version 2.5 or 2.6. Some caveats +Fabric requires `Python <http://python.org>`_ version 2.5 - 2.7. Some caveats and notes about other Python versions: * We are not planning on supporting **Python 2.4** given its age and the number diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/sites/www/roadmap.rst new/Fabric-1.10.2/sites/www/roadmap.rst --- old/Fabric-1.10.1/sites/www/roadmap.rst 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/sites/www/roadmap.rst 2015-06-19 20:18:33.000000000 +0200 @@ -13,8 +13,8 @@ Fabric 1.x ========== -Fabric 1.x, while not end-of-life'd, has reached a tipping point regarding -internal tech debt & ability to make significant improvements without harming +Fabric 1.x, while not quite yet end-of-life'd, has reached a tipping point +regarding internal tech debt & ability to make improvements without harming backwards compatibility. As such, future 1.x releases (**1.6** onwards) will emphasize small-to-medium @@ -31,25 +31,27 @@ <https://github.com/pyinvoke/invoke>`_ (see also :issue:`565`), which is a revamped and standalone version of Fabric's task running components. - * As of late 2013, Invoke is approaching maturity and already has a handful of + * As of early 2015, Invoke is already reasonably mature and has a handful of features lacking in Fabric itself, including but not limited to: * a more explicit and powerful namespacing implementation - * "regular" style CLI flags, + * "regular" style CLI flags, including powerful tab completion * before/after hooks - * explicit context management + * explicit context management (no shared state) + * significantly more powerful configuration mechanisms * Invoke is already Python 3 compatible, due to being a new codebase with few dependencies. - * As Fabric 2 is developed, Invoke will continue to grow & change to suit - Fabric's needs while remaining a high quality standalone task runner. + * As Fabric 2 is developed, Invoke will approach a 1.0 release, and will + continue to grow & change to suit Fabric's needs while remaining a high + quality standalone task runner. -* Start putting together Fabric 2.0, a mostly-rewritten Fabric core: +* Release Fabric 2.0, a mostly-rewritten Fabric core: * Leverage Invoke for task running, leaving Fabric itself much more library oriented. * Implement object-oriented hosts/host lists and all the fun stuff that - provides (e.g. no more hacky host string and unintuitive env var + provides (no more hacky host string and unintuitive env var manipulation.) * No more shared state by default (thanks to Invoke's context design.) * Any other core overhauls difficult to do in a backwards compatible diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/Python26SocketServer.py new/Fabric-1.10.2/tests/Python26SocketServer.py --- old/Fabric-1.10.1/tests/Python26SocketServer.py 2014-08-14 22:54:23.000000000 +0200 +++ new/Fabric-1.10.2/tests/Python26SocketServer.py 2015-05-04 02:23:37.000000000 +0200 @@ -118,6 +118,7 @@ entry is processed by a RequestHandlerClass. """ +# This file copyright (c) 2001-2015 Python Software Foundation; All Rights Reserved # Author of the BaseServer patch: Luke Kenneth Casson Leighton diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/support/aborts.py new/Fabric-1.10.2/tests/support/aborts.py --- old/Fabric-1.10.1/tests/support/aborts.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Fabric-1.10.2/tests/support/aborts.py 2015-05-04 03:23:07.000000000 +0200 @@ -0,0 +1,5 @@ +from fabric.api import task, abort + +@task +def kaboom(): + abort("It burns!") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/test_context_managers.py new/Fabric-1.10.2/tests/test_context_managers.py --- old/Fabric-1.10.1/tests/test_context_managers.py 2014-09-19 04:09:42.000000000 +0200 +++ new/Fabric-1.10.2/tests/test_context_managers.py 2015-05-04 02:23:37.000000000 +0200 @@ -9,7 +9,7 @@ from fabric.state import env, output from fabric.context_managers import (cd, settings, lcd, hide, shell_env, quiet, warn_only, prefix, path) -from fabric.operations import run, local +from fabric.operations import run, local, _prefix_commands from utils import mock_streams, FabricTest from server import server @@ -110,6 +110,35 @@ with cm2: eq_(env.command_prefixes, ['1', '2']) +# +# cd prefix with dev/null +# + +def test_cd_prefix(): + """ + cd prefix should direct output to /dev/null in case of CDPATH + """ + some_path = "~/somepath" + + with cd(some_path): + command_out = _prefix_commands('foo', "remote") + eq_(command_out, 'cd %s >/dev/null && foo' % some_path) + + +# def test_cd_prefix_on_win32(): +# """ +# cd prefix should NOT direct output to /dev/null on win32 +# """ +# some_path = "~/somepath" + +# import fabric +# try: +# fabric.state.win32 = True +# with cd(some_path): +# command_out = _prefix_commands('foo', "remote") +# eq_(command_out, 'cd %s && foo' % some_path) +# finally: +# fabric.state.win32 = False # # hide/show diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/test_network.py new/Fabric-1.10.2/tests/test_network.py --- old/Fabric-1.10.1/tests/test_network.py 2014-09-19 05:11:49.000000000 +0200 +++ new/Fabric-1.10.2/tests/test_network.py 2015-04-30 04:32:40.000000000 +0200 @@ -16,7 +16,6 @@ import fabric.network # So I can call patch_object correctly. Sigh. from fabric.state import env, output, _get_system_username from fabric.operations import run, sudo, prompt -from fabric.exceptions import NetworkError from fabric.tasks import execute from fabric.api import parallel from fabric import utils # for patching diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/test_tasks.py new/Fabric-1.10.2/tests/test_tasks.py --- old/Fabric-1.10.1/tests/test_tasks.py 2014-12-20 00:19:16.000000000 +0100 +++ new/Fabric-1.10.2/tests/test_tasks.py 2015-05-04 02:23:37.000000000 +0200 @@ -10,7 +10,7 @@ import fabric from fabric.tasks import WrappedCallableTask, execute, Task, get_task_details from fabric.main import display_command -from fabric.api import run, env, settings, hosts, roles, hide, parallel, task +from fabric.api import run, env, settings, hosts, roles, hide, parallel, task, runs_once, serial from fabric.network import from_dict from fabric.exceptions import NetworkError @@ -466,6 +466,9 @@ class TestTaskDetails(unittest.TestCase): def test_old_style_task_with_default_args(self): + """ + __details__() should print docstr for old style task methods with default args + """ def task_old_style(arg1, arg2, arg3=None, arg4='yes'): '''Docstring''' details = get_task_details(task_old_style) @@ -474,6 +477,10 @@ details) def test_old_style_task_without_default_args(self): + """ + __details__() should print docstr for old style task methods without default args + """ + def task_old_style(arg1, arg2): '''Docstring''' details = get_task_details(task_old_style) @@ -482,6 +489,10 @@ details) def test_old_style_task_without_args(self): + """ + __details__() should print docstr for old style task methods without args + """ + def task_old_style(): '''Docstring''' details = get_task_details(task_old_style) @@ -490,14 +501,43 @@ details) def test_decorated_task(self): + """ + __details__() should print docstr for method with any number and order of decorations + """ + expected = "\n".join([ + "Docstring", + "Arguments: arg1", + ]) + @task def decorated_task(arg1): '''Docstring''' - eq_("Docstring\n" - "Arguments: arg1", - decorated_task.__details__()) + + actual = decorated_task.__details__() + eq_(expected, actual) + + @runs_once + @task + def decorated_task1(arg1): + '''Docstring''' + + actual = decorated_task1.__details__() + eq_(expected, actual) + + @runs_once + @serial + @task + def decorated_task2(arg1): + '''Docstring''' + + actual = decorated_task2.__details__() + eq_(expected, actual) def test_subclassed_task(self): + """ + __details__() should print docstr for subclassed task methods with args + """ + class SpecificTask(Task): def run(self, arg1, arg2, arg3): '''Docstring''' @@ -507,6 +547,10 @@ @mock_streams('stdout') def test_multiline_docstring_indented_correctly(self): + """ + display_command() should properly indent docstr for old style task methods + """ + def mytask(arg1): """ This is a multi line docstring. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Fabric-1.10.1/tests/test_utils.py new/Fabric-1.10.2/tests/test_utils.py --- old/Fabric-1.10.1/tests/test_utils.py 2014-12-19 19:39:38.000000000 +0100 +++ new/Fabric-1.10.2/tests/test_utils.py 2015-05-04 03:23:07.000000000 +0200 @@ -1,6 +1,7 @@ from __future__ import with_statement import sys +import traceback from unittest import TestCase from fudge import Fake, patched_context, with_fakes @@ -10,9 +11,11 @@ from fabric.state import output, env from fabric.utils import warn, indent, abort, puts, fastprint, error, RingBuffer from fabric import utils # For patching +from fabric.api import local, quiet from fabric.context_managers import settings, hide from fabric.colors import magenta, red -from utils import mock_streams, aborts, FabricTest, assert_contains +from utils import mock_streams, aborts, FabricTest, assert_contains, \ + assert_not_contains @mock_streams('stderr') @@ -70,7 +73,6 @@ with settings(abort_exception=TestException): abort("Test") - @mock_streams('stderr') @with_patched_object(output, 'aborts', True) def test_abort_message(): @@ -84,6 +86,31 @@ result = sys.stderr.getvalue() eq_("\nFatal error: Test\n\nAborting.\n", result) +def test_abort_message_only_printed_once(): + """ + abort()'s SystemExit should not cause a reprint of the error message + """ + # No good way to test the implicit stderr print which sys.exit/SystemExit + # perform when they are allowed to bubble all the way to the top. So, we + # invoke a subprocess and look at its stderr instead. + with quiet(): + result = local("fab -f tests/support/aborts.py kaboom", capture=True) + # When error in #1318 is present, this has an extra "It burns!" at end of + # stderr string. + eq_(result.stderr, "Fatal error: It burns!\n\nAborting.") + +@mock_streams('stderr') +@with_patched_object(output, 'aborts', True) +def test_abort_exception_contains_separate_message_and_code(): + """ + abort()'s SystemExit contains distinct .code/.message attributes. + """ + # Re #1318 / #1213 + try: + abort("Test") + except SystemExit as e: + eq_(e.message, "Test") + eq_(e.code, 1) @mock_streams('stdout') def test_puts_with_user_output_on(): @@ -163,6 +190,8 @@ class TestErrorHandling(FabricTest): + dummy_string = 'test1234!' + @with_patched_object(utils, 'warn', Fake('warn', callable=True, expect_call=True)) def test_error_warns_if_warn_only_True_and_func_None(self): @@ -200,6 +229,45 @@ error("error message", func=utils.abort, stdout=stdout) assert_contains(stdout, sys.stdout.getvalue()) + @mock_streams('stdout') + @with_patched_object(utils, 'abort', Fake('abort', callable=True, + expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) + @with_patched_object(output, 'exceptions', True) + @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, + expect_call=True).returns(dummy_string)) + def test_includes_traceback_if_exceptions_logging_is_on(self): + """ + error() includes traceback in message if exceptions logging is on + """ + error("error message", func=utils.abort, stdout=error) + assert_contains(self.dummy_string, sys.stdout.getvalue()) + + @mock_streams('stdout') + @with_patched_object(utils, 'abort', Fake('abort', callable=True, + expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) + @with_patched_object(output, 'debug', True) + @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, + expect_call=True).returns(dummy_string)) + def test_includes_traceback_if_debug_logging_is_on(self): + """ + error() includes traceback in message if debug logging is on (backwardis compatibility) + """ + error("error message", func=utils.abort, stdout=error) + assert_contains(self.dummy_string, sys.stdout.getvalue()) + + @mock_streams('stdout') + @with_patched_object(utils, 'abort', Fake('abort', callable=True, + expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) + @with_patched_object(output, 'exceptions', True) + @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, + expect_call=True).returns(None)) + def test_doesnt_print_None_when_no_traceback_present(self): + """ + error() doesn't include None in message if there is no traceback + """ + error("error message", func=utils.abort, stdout=error) + assert_not_contains('None', sys.stdout.getvalue()) + @mock_streams('stderr') @with_patched_object(utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stderr.write(x + "\n")))
