Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-Fabric for openSUSE:Factory 
checked in at 2023-07-03 17:43:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Fabric (Old)
 and      /work/SRC/openSUSE:Factory/.python-Fabric.new.13546 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Fabric"

Mon Jul  3 17:43:01 2023 rev:43 rq:1096411 version:3.0.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Fabric/python-Fabric.changes      
2023-07-01 23:18:19.398358153 +0200
+++ /work/SRC/openSUSE:Factory/.python-Fabric.new.13546/python-Fabric.changes   
2023-07-03 17:43:03.808816802 +0200
@@ -1,0 +2,28 @@
+Sun Jul  2 08:57:33 UTC 2023 - ecsos <[email protected]>
+
+- Update to 3.0.1
+  * [Bug] #2241: A typo prevented Fabric’s command runner from properly
+    calling its superclass stop() method, which in tandem with a related
+    Invoke bug meant messy or long shutdowns in many scenarios.
+- Changes from 3.0.0
+  * [Feature]: Change the default configuration value for inline_ssh_env
+    from False to True, to better align with the practicalities of common
+    SSH server configurations.
+    - Warning
+      This change is backwards incompatible if you were using 
+      environment-variable-setting kwargs or config settings,
+      such as Connection.run(command, env={'SOME': 'ENV VARS'}),
+      and were not already explicitly specifying the value of inline_ssh_env.
+  * [Bug] #1981: (fixed in #2195) Automatically close any open SFTP session
+    during fabric.connection.Connection.close; this avoids issues encountered
+    upon re-opening a previously-closed connection object.
+  * [Support]: Drop support for Python <3.6, including Python 2.
+    - Warning
+      This is a backwards incompatible change if you are not yet on
+      Python 3.6 or above; however, pip shouldn’t offer you this
+      version of Fabric as long as your pip version understands
+      python_requires metadata.
+- Drop remove-mock.patch because now in upstream.
+- Drop remove-pathlib2.patch because now in upstream.
+
+-------------------------------------------------------------------

Old:
----
  fabric-2.7.1.tar.gz
  remove-mock.patch
  remove-pathlib2.patch

New:
----
  fabric-3.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Fabric.spec ++++++
--- /var/tmp/diff_new_pack.MtlOSC/_old  2023-07-03 17:43:04.428820453 +0200
+++ /var/tmp/diff_new_pack.MtlOSC/_new  2023-07-03 17:43:04.432820476 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-Fabric
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-Fabric
-Version:        2.7.1
+Version:        3.0.1
 Release:        0
 Summary:        A Pythonic tool for remote execution and deployment
 License:        BSD-2-Clause
@@ -26,25 +26,16 @@
 Source:         
https://files.pythonhosted.org/packages/source/f/fabric/fabric-%{version}.tar.gz
 # PATCH-FIX-UPSTREAM gh#fabric/fabric#2209
 Patch0:         fix-executable.patch
-# PATCH-FIX-UPSTREAM gh#fabric/fabric#2210
-Patch1:         remove-mock.patch
-# PATCH-FIX-OPENSUSE remove pathlib2 requirement gh#fabric/fabric#2180
-Patch2:         remove-pathlib2.patch
-BuildRequires:  %{python_module cryptography >= 1.1}
 BuildRequires:  %{python_module decorator}
-BuildRequires:  %{python_module invoke >= 1.3}
+BuildRequires:  %{python_module invoke >= 2.0}
 BuildRequires:  %{python_module paramiko >= 2.4}
 BuildRequires:  %{python_module pytest-relaxed}
 BuildRequires:  %{python_module setuptools}
-BuildRequires:  %{python_module six}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-cryptography >= 1.1
 Requires:       python-decorator
-Requires:       python-invoke >= 1.3
+Requires:       python-invoke >= 2.0
 Requires:       python-paramiko >= 2.4
-Requires:       python-setuptools
-Requires:       python-six
 Requires(post): update-alternatives
 Requires(postun):update-alternatives
 Conflicts:      python-Fabric3

++++++ fabric-2.7.1.tar.gz -> fabric-3.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/PKG-INFO new/fabric-3.0.1/PKG-INFO
--- old/fabric-2.7.1/PKG-INFO   2022-07-15 00:39:03.000000000 +0200
+++ new/fabric-3.0.1/PKG-INFO   2023-04-29 20:59:33.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: fabric
-Version: 2.7.1
+Version: 3.0.1
 Summary: High level SSH command execution
 Home-page: https://fabfile.org
 Author: Jeff Forcier
@@ -57,13 +57,14 @@
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Operating System :: Microsoft :: Windows
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Topic :: Software Development
 Classifier: Topic :: Software Development :: Build Tools
 Classifier: Topic :: Software Development :: Libraries
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/dev-requirements.txt 
new/fabric-3.0.1/dev-requirements.txt
--- old/fabric-2.7.1/dev-requirements.txt       2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/dev-requirements.txt       2023-04-28 17:33:01.000000000 
+0200
@@ -1,24 +1,19 @@
 # Us, of course
 -e .
+paramiko>=3.0
+invoke>=2.0
 # Invocations for common project tasks
-invocations==2.6.0
+invocations>=3.0.1
 # pytest-relaxed for test organization, display etc tweaks
-pytest-relaxed>=1.0.1,<1.1
-pytest==3.2.5
+pytest-relaxed>=2
 # pytest-cov for coverage
-pytest-cov==2.5.1
-six==1.10.0
-# Mock for test mocking
-mock==2.0.0
-# Formatting!
-flake8==3.6.0
-black==18.6b4
+pytest-cov>=4
+# Formatting
+# Flake8 5.x seems to have an odd importlib-metadata incompatibility?
+flake8>=4,<5
+black>=22.8,<22.9
 # Coverage!
-coverage==5.3.1
-codecov==2.1.11
+coverage>=6.2,<7
 # Documentation tools
-sphinx>=1.4,<1.7
-alabaster==0.7.12
-releases>=1.5,<2.0
-# Release tools
-semantic_version>=2.4,<2.5
+releases>=2
+alabaster==0.7.13
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/_version.py 
new/fabric-3.0.1/fabric/_version.py
--- old/fabric-2.7.1/fabric/_version.py 2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/fabric/_version.py 2023-04-29 20:58:51.000000000 +0200
@@ -1,2 +1,2 @@
-__version_info__ = (2, 7, 1)
+__version_info__ = (3, 0, 1)
 __version__ = ".".join(map(str, __version_info__))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/config.py 
new/fabric-3.0.1/fabric/config.py
--- old/fabric-2.7.1/fabric/config.py   2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/fabric/config.py   2023-04-29 19:40:23.000000000 +0200
@@ -156,7 +156,7 @@
 
         # Now that our own attributes have been prepared & kwargs yanked, we
         # can fall up into parent __init__()
-        super(Config, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
         # And finally perform convenience non-lazy bits if needed
         if not lazy:
@@ -202,7 +202,7 @@
         # .base_ssh_config ourselves. Similarly, there's no need to worry about
         # how the SSH config paths may be inaccurate until below; nothing will
         # be referencing them.
-        new = super(Config, self).clone(*args, **kwargs)
+        new = super().clone(*args, **kwargs)
         # Copy over our custom attributes, so that the clone still resembles us
         # re: recording where the data originally came from (in case anything
         # re-runs ._load_ssh_files(), for example).
@@ -220,7 +220,7 @@
 
     def _clone_init_kwargs(self, *args, **kw):
         # Parent kwargs
-        kwargs = super(Config, self)._clone_init_kwargs(*args, **kw)
+        kwargs = super()._clone_init_kwargs(*args, **kw)
         # Transmit our internal SSHConfig via explicit-obj kwarg, thus
         # bypassing any file loading. (Our extension of clone() above copies
         # over other attributes as well so that the end result looks consistent
@@ -247,8 +247,9 @@
             path = self._runtime_ssh_path
             # Manually blow up like open() (_load_ssh_file normally doesn't)
             if not os.path.exists(path):
-                msg = "No such file or directory: {!r}".format(path)
-                raise IOError(errno.ENOENT, msg)
+                raise FileNotFoundError(
+                    errno.ENOENT, "No such file or directory", path
+                )
             self._load_ssh_file(os.path.expanduser(path))
         elif self.load_ssh_configs:
             for path in (self._user_ssh_path, self._system_ssh_path):
@@ -304,8 +305,7 @@
             "connect_kwargs": {},
             "forward_agent": False,
             "gateway": None,
-            # TODO 3.0: change to True and update all docs accordingly.
-            "inline_ssh_env": False,
+            "inline_ssh_env": True,
             "load_ssh_configs": True,
             "port": 22,
             "runners": {"remote": Remote, "remote_shell": RemoteShell},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/connection.py 
new/fabric-3.0.1/fabric/connection.py
--- old/fabric-2.7.1/fabric/connection.py       2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/fabric/connection.py       2023-04-29 19:40:23.000000000 
+0200
@@ -1,15 +1,12 @@
 from contextlib import contextmanager
+from io import StringIO
 from threading import Event
+import socket
 
 try:
-    from invoke.vendor.six import StringIO
     from invoke.vendor.decorator import decorator
-    from invoke.vendor.six import string_types
 except ImportError:
-    from six import StringIO
     from decorator import decorator
-    from six import string_types
-import socket
 
 from invoke import Context
 from invoke.exceptions import ThreadException
@@ -327,15 +324,19 @@
 
         :param bool inline_ssh_env:
             Whether to send environment variables "inline" as prefixes in front
-            of command strings (``export VARNAME=value && mycommand here``),
-            instead of trying to submit them through the SSH protocol itself
-            (which is the default behavior). This is necessary if the remote
-            server has a restricted ``AcceptEnv`` setting (which is the common
-            default).
-
-            The default value is the value of the ``inline_ssh_env``
-            :ref:`configuration value <default-values>` (which itself defaults
-            to ``False``).
+            of command strings (``export VARNAME=value && mycommand here``;
+            this is the default behavior), or submit them through the SSH
+            protocol itself.
+
+            In Fabric 2.x this defaulted to ``False`` (try using the protocol
+            behavior), but in 3.x it changed to ``True`` due to the simple fact
+            that most remote servers are deployed with a restricted
+            ``AcceptEnv`` setting, making use of the protocol approach
+            non-viable.
+
+            The actual default value is the value of the ``inline_ssh_env``
+            :ref:`configuration value <default-values>` (which, as above,
+            currently defaults to ``True``).
 
             .. warning::
                 This functionality does **not** currently perform any shell
@@ -366,11 +367,16 @@
 
         .. versionchanged:: 2.3
             Added the ``inline_ssh_env`` parameter.
+
+        .. versionchanged:: 3.0
+            ``inline_ssh_env`` still defaults to the config value, but said
+            config value has now changed and defaults to ``True``, not
+            ``False``.
         """
         # NOTE: parent __init__ sets self._config; for now we simply overwrite
         # that below. If it's somehow problematic we would want to break parent
         # __init__ up in a manner that is more cleanly overrideable.
-        super(Connection, self).__init__(config=config)
+        super().__init__(config=config)
 
         #: The .Config object referenced when handling default values (for e.g.
         #: user or port, when not explicitly given) or deciding how to behave.
@@ -486,7 +492,7 @@
         # Make sure all are normalized to list as well!
         final_keys = []
         for value in (config_keys, constructor_keys, ssh_config_keys):
-            if isinstance(value, string_types):
+            if isinstance(value, str):
                 value = [value]
             final_keys.extend(value)
         # Only populate if non-empty.
@@ -543,7 +549,7 @@
         if self.gateway:
             # Displaying type because gw params would probs be too verbose
             val = "proxyjump"
-            if isinstance(self.gateway, string_types):
+            if isinstance(self.gateway, str):
                 val = "proxycommand"
             bits.append(("gw", val))
         return "<Connection {}>".format(
@@ -648,7 +654,7 @@
         .. versionadded:: 2.0
         """
         # ProxyCommand is faster to set up, so do it first.
-        if isinstance(self.gateway, string_types):
+        if isinstance(self.gateway, str):
             # Leverage a dummy SSHConfig to ensure %h/%p/etc are parsed.
             # TODO: use real SSH config once loading one properly is
             # implemented.
@@ -680,10 +686,18 @@
         """
         Terminate the network connection to the remote end, if open.
 
-        If no connection is open, this method does nothing.
+        If any SFTP sessions are open, they will also be closed.
+
+        If no connection or SFTP session is open, this method does nothing.
 
         .. versionadded:: 2.0
+        .. versionchanged:: 3.0
+            Now closes SFTP sessions too (2.x required manually doing so).
         """
+        if self._sftp is not None:
+            self._sftp.close()
+            self._sftp = None
+
         if self.is_connected:
             self.client.close()
             if self.forward_agent and self._agent_handler is not None:
@@ -829,7 +843,7 @@
         """
         # Superclass run() uses runners.local, so we can literally just call it
         # straight.
-        return super(Connection, self).run(*args, **kwargs)
+        return super().run(*args, **kwargs)
 
     @opens
     def sftp(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/group.py 
new/fabric-3.0.1/fabric/group.py
--- old/fabric-2.7.1/fabric/group.py    2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/fabric/group.py    2023-01-21 00:13:54.000000000 +0100
@@ -1,7 +1,4 @@
-try:
-    from invoke.vendor.six.moves.queue import Queue
-except ImportError:
-    from six.moves.queue import Queue
+from queue import Queue
 
 from invoke.util import ExceptionHandlingThread
 
@@ -180,9 +177,8 @@
 
         .. versionadded:: 2.6
         """
-        # TODO: consider a backwards incompat change after we drop Py2 that
-        # just makes a lot of these kwarg-only methods? then below could become
-        # kwargs.setdefault() if desired.
+        # TODO 4.0: consider making many of these into kwarg-only methods? then
+        # below could become kwargs.setdefault() if desired.
         # TODO: do we care enough to handle explicitly given, yet falsey,
         # values? it's a lot more complexity for a corner case.
         if len(args) < 2 and "local" not in kwargs:
@@ -309,7 +305,7 @@
     """
 
     def __init__(self, *args, **kwargs):
-        super(dict, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self._successes = {}
         self._failures = {}
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/main.py 
new/fabric-3.0.1/fabric/main.py
--- old/fabric-2.7.1/fabric/main.py     2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/fabric/main.py     2023-04-29 19:40:23.000000000 +0200
@@ -16,12 +16,12 @@
 
 class Fab(Program):
     def print_version(self):
-        super(Fab, self).print_version()
+        super().print_version()
         print("Paramiko {}".format(paramiko))
         print("Invoke {}".format(invoke))
 
     def core_args(self):
-        core_args = super(Fab, self).core_args()
+        core_args = super().core_args()
         my_args = [
             Argument(
                 names=("H", "hosts"),
@@ -84,13 +84,13 @@
             # honor the real "lives by task coll"?
             self.collection = Collection()
         else:
-            super(Fab, self).load_collection()
+            super().load_collection()
 
     def no_tasks_given(self):
         # As above, neuter the usual "hey you didn't give me any tasks, let me
         # print help for you" behavior, if necessary.
         if not self._remainder_only:
-            super(Fab, self).no_tasks_given()
+            super().no_tasks_given()
 
     def create_config(self):
         # Create config, as parent does, but with lazy=True to avoid our own
@@ -112,7 +112,7 @@
         # Note runtime SSH path, if given, and load SSH configurations.
         # NOTE: must do parent before our work, in case users want to disable
         # SSH config loading within a runtime-level conf file/flag.
-        super(Fab, self).update_config(merge=False)
+        super().update_config(merge=False)
         self.config.set_runtime_ssh_path(self.args["ssh-config"].value)
         self.config.load_ssh_config()
         # Load -i identity file, if given, into connect_kwargs, at overrides
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/runners.py 
new/fabric-3.0.1/fabric/runners.py
--- old/fabric-2.7.1/fabric/runners.py  2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/fabric/runners.py  2023-04-29 19:52:38.000000000 +0200
@@ -26,13 +26,16 @@
         :param bool inline_env:
             Whether to 'inline' shell env vars as prefixed parameters, instead
             of trying to submit them via `.Channel.update_environment`.
-            Default:: ``False``.
+            Default: ``True``.
 
         .. versionchanged:: 2.3
             Added the ``inline_env`` parameter.
+        .. versionchanged:: 3.0
+            Changed the default value of ``inline_env`` from ``False`` to
+            ``True``.
         """
         self.inline_env = kwargs.pop("inline_env", None)
-        super(Remote, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
     def start(self, command, shell, env, timeout=None):
         self.channel = self.context.create_session()
@@ -69,7 +72,7 @@
 
     def run(self, command, **kwargs):
         kwargs.setdefault("replace_env", True)
-        return super(Remote, self).run(command, **kwargs)
+        return super().run(command, **kwargs)
 
     def read_proc_stdout(self, num_bytes):
         return self.channel.recv(num_bytes)
@@ -99,7 +102,7 @@
             # Submit hex ASCII character 3, aka ETX, which most Unix PTYs
             # interpret as a foreground SIGINT.
             # TODO: is there anything else we can do here to be more portable?
-            self.channel.send(u"\x03")
+            self.channel.send("\x03")
         else:
             raise interrupt
 
@@ -111,6 +114,7 @@
         return Result(**kwargs)
 
     def stop(self):
+        super().stop()
         if hasattr(self, "channel"):
             self.channel.close()
 
@@ -168,7 +172,7 @@
 
     def __init__(self, **kwargs):
         connection = kwargs.pop("connection")
-        super(Result, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.connection = connection
 
     # TODO: have useful str/repr differentiation from invoke.Result,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/tasks.py 
new/fabric-3.0.1/fabric/tasks.py
--- old/fabric-2.7.1/fabric/tasks.py    2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/fabric/tasks.py    2023-01-21 00:13:54.000000000 +0100
@@ -18,7 +18,7 @@
         # Pull out our own kwargs before hitting super, which will TypeError on
         # anything it doesn't know about.
         self.hosts = kwargs.pop("hosts", None)
-        super(Task, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
 
 def task(*args, **kwargs):
@@ -88,7 +88,7 @@
             wrapped task is executed. Default: ``None``.
         """
         init_kwargs = kwargs.pop("init_kwargs")  # , None)
-        super(ConnectionCall, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.init_kwargs = init_kwargs
 
     def clone_kwargs(self):
@@ -97,7 +97,7 @@
         # without getting too crazy on the metaprogramming/over-engineering?
         # Maybe something attrs library can help with (re: declaring "These are
         # my bag-of-attributes attributes I want common stuff done to/with")
-        kwargs = super(ConnectionCall, self).clone_kwargs()
+        kwargs = super().clone_kwargs()
         kwargs["init_kwargs"] = self.init_kwargs
         return kwargs
 
@@ -110,7 +110,7 @@
         return Connection(**kwargs)
 
     def __repr__(self):
-        ret = super(ConnectionCall, self).__repr__()
+        ret = super().__repr__()
         if self.init_kwargs:
             ret = ret[:-1] + ", host='{}'>".format(self.init_kwargs["host"])
         return ret
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/testing/base.py 
new/fabric-3.0.1/fabric/testing/base.py
--- old/fabric-2.7.1/fabric/testing/base.py     2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/fabric/testing/base.py     2023-01-21 00:13:54.000000000 
+0100
@@ -2,9 +2,9 @@
 This module contains helpers/fixtures to assist in testing Fabric-driven code.
 
 It is not intended for production use, and pulls in some test-oriented
-dependencies such as `mock <https://pypi.org/project/mock/>`_. You can install
-an 'extra' variant of Fabric to get these dependencies if you aren't already
-using them for your own testing purposes: ``pip install fabric[testing]``.
+dependencies as needed. You can install an 'extra' variant of Fabric to get
+these dependencies if you aren't already using them for your own testing
+purposes: ``pip install fabric[testing]``.
 
 .. note::
     If you're using pytest for your test suite, you may be interested in
@@ -19,20 +19,10 @@
 from io import BytesIO
 import os
 
-try:
-    from mock import Mock, PropertyMock, call, patch, ANY
-except ImportError:
-    import warnings
-
-    warning = (
-        "You appear to be missing some optional test-related dependencies;"
-        "please 'pip install fabric[testing]'."
-    )
-    warnings.warn(warning, ImportWarning)
-    raise
+from unittest.mock import Mock, PropertyMock, call, patch, ANY
 
 
-class Command(object):
+class Command:
     """
     Data record specifying params of a command execution to mock/expect.
 
@@ -104,7 +94,7 @@
         object.__setattr__(self, "__stderr", kwargs.pop("stderr"))
         # Stdin less private so it can be asserted about
         object.__setattr__(self, "_stdin", BytesIO())
-        super(MockChannel, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
     def _get_child_mock(self, **kwargs):
         # Don't return our own class on sub-mocks.
@@ -120,7 +110,7 @@
         return object.__getattribute__(self, "_stdin").write(data)
 
 
-class Session(object):
+class Session:
     """
     A mock remote session of a single connection and 1 or more command execs.
 
@@ -284,7 +274,7 @@
         assert calls == session_opens
 
 
-class MockRemote(object):
+class MockRemote:
     """
     Class representing mocked remote state.
 
@@ -377,7 +367,7 @@
 
 # TODO: unify with the stuff in paramiko itself (now in its tests/conftest.py),
 # they're quite distinct and really shouldn't be.
-class MockSFTP(object):
+class MockSFTP:
     """
     Class managing mocked SFTP remote state.
 
@@ -409,8 +399,8 @@
 
         mock_os.path.abspath.side_effect = fake_abspath
         sftp.getcwd.return_value = "/remote"
-        # Ensure stat st_mode is a real number; Python 2 stat.S_IMODE doesn't
-        # appear to care if it's handed a MagicMock, but Python 3's does (?!)
+        # Ensure stat st_mode is a real number; Python 3's stat.S_IMODE doesn't
+        # like just being handed a MagicMock?
         fake_mode = 0o644  # arbitrary real-ish mode
         sftp.stat.return_value.st_mode = fake_mode
         mock_os.stat.return_value.st_mode = fake_mode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/testing/fixtures.py 
new/fabric-3.0.1/fabric/testing/fixtures.py
--- old/fabric-2.7.1/fabric/testing/fixtures.py 2021-12-05 00:24:42.000000000 
+0100
+++ new/fabric-3.0.1/fabric/testing/fixtures.py 2023-01-21 00:13:54.000000000 
+0100
@@ -15,9 +15,10 @@
 .. versionadded:: 2.1
 """
 
+from unittest.mock import patch, Mock
+
 try:
     from pytest import fixture
-    from mock import patch, Mock
 except ImportError:
     import warnings
 
@@ -31,10 +32,6 @@
 from .. import Connection
 from ..transfer import Transfer
 
-# TODO: if we find a lot of people somehow ending up _with_ pytest but
-# _without_ mock and other deps from testing.base, consider doing the
-# try/except here too. But, really?
-
 from .base import MockRemote, MockSFTP
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/transfer.py 
new/fabric-3.0.1/fabric/transfer.py
--- old/fabric-2.7.1/fabric/transfer.py 2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/fabric/transfer.py 2023-01-21 00:13:54.000000000 +0100
@@ -6,10 +6,7 @@
 import posixpath
 import stat
 
-try:
-    from pathlib import Path
-except ImportError:
-    from pathlib2 import Path
+from pathlib import Path
 
 from .util import debug  # TODO: actual logging! LOL
 
@@ -21,7 +18,7 @@
 # course.
 
 
-class Transfer(object):
+class Transfer:
     """
     `.Connection`-wrapping class responsible for managing file upload/download.
 
@@ -326,7 +323,7 @@
         )
 
 
-class Result(object):
+class Result:
     """
     A container for information about the result of a file transfer.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric/tunnels.py 
new/fabric-3.0.1/fabric/tunnels.py
--- old/fabric-2.7.1/fabric/tunnels.py  2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/fabric/tunnels.py  2023-01-21 00:13:54.000000000 +0100
@@ -5,7 +5,6 @@
 see `.Connection`, e.g. `.Connection.forward_local`.
 """
 
-import errno
 import select
 import socket
 import time
@@ -39,7 +38,7 @@
         transport,
         finished,
     ):
-        super(TunnelManager, self).__init__()
+        super().__init__()
         self.local_address = (local_host, local_port)
         self.remote_address = (remote_host, remote_port)
         self.transport = transport
@@ -68,12 +67,10 @@
                 tun_sock, local_addr = sock.accept()
                 # Set TCP_NODELAY to match OpenSSH's forwarding socket behavior
                 tun_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-            except socket.error as e:
-                if e.errno is errno.EAGAIN:
-                    # TODO: make configurable
-                    time.sleep(0.01)
-                    continue
-                raise
+            except BlockingIOError:  # ie errno.EAGAIN
+                # TODO: make configurable
+                time.sleep(0.01)
+                continue
 
             # Set up direct-tcpip channel on server end
             # TODO: refactor w/ what's used for gateways
@@ -122,7 +119,7 @@
         self.finished = finished
         self.socket_chunk_size = 1024
         self.channel_chunk_size = 1024
-        super(Tunnel, self).__init__()
+        super().__init__()
 
     def _run(self):
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric.egg-info/PKG-INFO 
new/fabric-3.0.1/fabric.egg-info/PKG-INFO
--- old/fabric-2.7.1/fabric.egg-info/PKG-INFO   2022-07-15 00:39:03.000000000 
+0200
+++ new/fabric-3.0.1/fabric.egg-info/PKG-INFO   2023-04-29 20:59:32.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: fabric
-Version: 2.7.1
+Version: 3.0.1
 Summary: High level SSH command execution
 Home-page: https://fabfile.org
 Author: Jeff Forcier
@@ -57,13 +57,14 @@
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Operating System :: Microsoft :: Windows
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Topic :: Software Development
 Classifier: Topic :: Software Development :: Build Tools
 Classifier: Topic :: Software Development :: Libraries
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric.egg-info/SOURCES.txt 
new/fabric-3.0.1/fabric.egg-info/SOURCES.txt
--- old/fabric-2.7.1/fabric.egg-info/SOURCES.txt        2022-07-15 
00:39:03.000000000 +0200
+++ new/fabric-3.0.1/fabric.egg-info/SOURCES.txt        2023-04-29 
20:59:32.000000000 +0200
@@ -2,7 +2,6 @@
 MANIFEST.in
 README.rst
 dev-requirements.txt
-setup.cfg
 setup.py
 tasks.py
 fabric/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/fabric.egg-info/requires.txt 
new/fabric-3.0.1/fabric.egg-info/requires.txt
--- old/fabric-2.7.1/fabric.egg-info/requires.txt       2022-07-15 
00:39:03.000000000 +0200
+++ new/fabric-3.0.1/fabric.egg-info/requires.txt       2023-04-29 
20:59:32.000000000 +0200
@@ -1,10 +1,7 @@
-invoke<2.0,>=1.3
+invoke>=2.0
 paramiko>=2.4
-pathlib2
 
 [pytest]
-mock<3.0,>=2.0.0
-pytest<4.0,>=3.2.5
+pytest>=7
 
 [testing]
-mock<3.0,>=2.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/integration/concurrency.py 
new/fabric-3.0.1/integration/concurrency.py
--- old/fabric-2.7.1/integration/concurrency.py 2021-12-05 00:24:42.000000000 
+0100
+++ new/fabric-3.0.1/integration/concurrency.py 2023-01-21 00:13:54.000000000 
+0100
@@ -1,7 +1,6 @@
 import codecs
-
-from invoke.vendor.six.moves.queue import Queue
-from invoke.vendor.six.moves import zip_longest
+from itertools import zip_longest
+from queue import Queue
 
 from invoke.util import ExceptionHandlingThread
 from pytest import skip
@@ -85,7 +84,7 @@
         while not queue.empty():
             cxn, result, expected = queue.get(block=False)
             for resultword, expectedword in zip_longest(result, expected):
-                err = u"({2!r}, {3!r}->{4!r}) {0!r} != {1!r}".format(
+                err = "({2!r}, {3!r}->{4!r}) {0!r} != {1!r}".format(
                     resultword, expectedword, cxn, expected[0], expected[-1]
                 )
                 assert resultword == expectedword, err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/integration/connection.py 
new/fabric-3.0.1/integration/connection.py
--- old/fabric-2.7.1/integration/connection.py  2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/integration/connection.py  2023-01-21 00:13:54.000000000 
+0100
@@ -1,10 +1,7 @@
 import os
 import time
 
-try:
-    from invoke.vendor.six import StringIO
-except ImportError:
-    from six import StringIO
+from io import StringIO
 
 from invoke import pty_size, CommandTimedOut
 from invocations.environment import in_ci
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/setup.cfg new/fabric-3.0.1/setup.cfg
--- old/fabric-2.7.1/setup.cfg  2022-07-15 00:39:03.000000000 +0200
+++ new/fabric-3.0.1/setup.cfg  2023-04-29 20:59:33.000000000 +0200
@@ -1,9 +1,3 @@
-[wheel]
-universal = 1
-
-[metadata]
-license_file = LICENSE
-
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/setup.py new/fabric-3.0.1/setup.py
--- old/fabric-2.7.1/setup.py   2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/setup.py   2023-04-29 19:40:23.000000000 +0200
@@ -45,9 +45,6 @@
     exec(fp.read(), None, _locals)
 version = _locals["__version__"]
 
-testing_deps = ["mock>=2.0.0,<3.0"]
-pytest_deps = ["pytest>=3.2.5,<4.0"]
-
 setuptools.setup(
     name=package_name,
     version=version,
@@ -65,10 +62,14 @@
         "CI": "https://app.circleci.com/pipelines/github/fabric/fabric";,
         "Twitter": "https://twitter.com/pyfabric";,
     },
-    install_requires=["invoke>=1.3,<2.0", "paramiko>=2.4", "pathlib2"],
+    python_requres=">=3.6",
+    install_requires=["invoke>=2.0", "paramiko>=2.4"],
     extras_require={
-        "testing": testing_deps,
-        "pytest": testing_deps + pytest_deps,
+        # For folks who want to use fabric.testing package, eg
+        # MockRemote/MockSFTP
+        "testing": [],  # no longer (for now?) needs anything special
+        # For folks who want to use fabric.testing.fixtures' pytest fixtures
+        "pytest": ["pytest>=7"],
     },
     packages=packages,
     entry_points={
@@ -87,13 +88,14 @@
         "Operating System :: MacOS :: MacOS X",
         "Operating System :: Microsoft :: Windows",
         "Programming Language :: Python",
-        "Programming Language :: Python :: 2",
-        "Programming Language :: Python :: 2.7",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.4",
-        "Programming Language :: Python :: 3.5",
+        "Programming Language :: Python :: 3 :: Only",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
         "Topic :: Software Development",
         "Topic :: Software Development :: Build Tools",
         "Topic :: Software Development :: Libraries",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/docs/concepts/configuration.rst 
new/fabric-3.0.1/sites/docs/concepts/configuration.rst
--- old/fabric-2.7.1/sites/docs/concepts/configuration.rst      2022-07-15 
00:37:01.000000000 +0200
+++ new/fabric-3.0.1/sites/docs/concepts/configuration.rst      2023-04-29 
19:40:23.000000000 +0200
@@ -99,7 +99,7 @@
   specified. Default: ``22``.
 - ``inline_ssh_env``: Boolean serving as global default for the value of
   `.Connection`'s ``inline_ssh_env`` parameter; see its docs for details.
-  Default: ``False``.
+  Default: ``True``.
 - ``ssh_config_path``: Runtime SSH config path; see :ref:`ssh-config`. Default:
   ``None``.
 - ``timeouts``: Various timeouts, specifically:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/docs/conf.py 
new/fabric-3.0.1/sites/docs/conf.py
--- old/fabric-2.7.1/sites/docs/conf.py 2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/sites/docs/conf.py 2023-01-21 00:13:54.000000000 +0100
@@ -8,7 +8,16 @@
 
 # Enable & configure autodoc
 extensions.append("sphinx.ext.autodoc")
-autodoc_default_flags = ["members", "special-members"]
+# Autodoc settings
+autodoc_default_options = {
+    "members": True,
+    "special-members": True,
+}
+# TODO: consider documenting things like Remote.run usefully and
+# re-enabling this? new as of sphinx 1.7 and NOT the old behavior, so very
+# surprising in a bunch of spots right now, where it pulls in Invoke
+# docstrings that then have bad refs and so on.
+autodoc_inherit_docstrings = False
 
 # Default is 'local' building, but reference the public WWW site when building
 # under RTD.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/docs/getting-started.rst 
new/fabric-3.0.1/sites/docs/getting-started.rst
--- old/fabric-2.7.1/sites/docs/getting-started.rst     2021-12-05 
00:24:42.000000000 +0100
+++ new/fabric-3.0.1/sites/docs/getting-started.rst     2023-01-21 
00:13:54.000000000 +0100
@@ -191,8 +191,7 @@
 
 .. testsetup:: sudo
 
-    from __future__ import print_function
-    from mock import patch
+    from unittest.mock import patch
     gp_patcher = patch('getpass.getpass', side_effect=lambda x: print(x))
     gp_patcher.start()
     mock = MockRemote()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/shared_conf.py 
new/fabric-3.0.1/sites/shared_conf.py
--- old/fabric-2.7.1/sites/shared_conf.py       2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/sites/shared_conf.py       2023-01-21 00:13:54.000000000 
+0100
@@ -69,8 +69,7 @@
 
 # Regular settings
 project = "Fabric"
-year = datetime.now().year
-copyright = "%d Jeff Forcier" % year
+copyright = f"{datetime.now().year} Jeff Forcier"
 master_doc = "index"
 templates_path = ["_templates"]
 exclude_trees = ["_build"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/www/changelog-v1.rst 
new/fabric-3.0.1/sites/www/changelog-v1.rst
--- old/fabric-2.7.1/sites/www/changelog-v1.rst 2022-07-15 00:38:45.000000000 
+0200
+++ new/fabric-3.0.1/sites/www/changelog-v1.rst 2023-01-21 00:13:54.000000000 
+0100
@@ -6,6 +6,35 @@
     This is the changelog for the legacy 1.x version of Fabric. For the current
     (2.0+) changelog, please see :doc:`the main changelog </changelog>`.
 
+* :release:`1.15.0 <2022-04-07>`
+* :support:`-` Merge the longstanding ``fabric3`` fork back into our v1 branch
+  so users who'd rather port Fabric 1.x code to Python 3 before upgrading to
+  Fabric 2.x, are able to do so in a "blessed" manner.
+
+  This change includes making sure that the delta between the fork and our v1
+  branch still functions correctly & passes tests on both interpreters. It also
+  includes a basic CircleCI configuration to test on 3.6, 3.7 and 3.8, not that
+  we expect to be hosting many future commits on this side...
+
+  Major major thanks to Mathias Ertl for his work on the fork, all the
+  contributors on his side of the house during that time, and to Zachary Vance
+  for getting the reconciliation process rolling.
+
+  The changes folded in as part of this work (mostly taken from Mathias'
+  changelog) are as follows:
+
+  - Installation now requires Paramiko 1.17.0 or later.
+  - Fix ``UnicodeDecodeError`` when receiving remote data.
+  - Clean up imports in main code base and test suite.
+  - Add Python 2/3/3.5 classifiers in ``setup.py``.
+  - Replace ``fabric.utils.RingBuffer`` with ``collections.deque`` from stdlib.
+  - Under Python 3, Fabric implements its own version of ``contextlib.nested``
+    based on ``contextlib.ExitStack``, since it's no longer available in
+    Python3.
+
+      - Please note that it was removed with good reason, we do not encourage
+        you use it.
+
 * :release:`1.14.1 <2018-11-27>`
 * :bug:`1341` (via :issue:`1586`) Attempt to ``rm -f`` the temporary file used
   by ``put``'s sudo mode, when exceptions are encountered; previously, the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/www/changelog.rst 
new/fabric-3.0.1/sites/www/changelog.rst
--- old/fabric-2.7.1/sites/www/changelog.rst    2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/sites/www/changelog.rst    2023-04-29 20:58:49.000000000 
+0200
@@ -13,6 +13,33 @@
     Click those projects' names in this paragraph to visit their changelogs and
     see what you might get if you upgrade your dependencies.
 
+- :release:`3.0.1 <2023-04-29>`
+- :bug:`2241` A typo prevented Fabric's command runner from properly calling
+  its superclass ``stop()`` method, which in tandem with a related Invoke bug
+  meant messy or long shutdowns in many scenarios. Thanks to Orlando
+  Rodríguez for report and initial patch.
+- :release:`3.0.0 <2023-01-20>`
+- :bug:`1981 major` (fixed in :issue:`2195`) Automatically close any open SFTP
+  session during `fabric.connection.Connection.close`; this avoids issues
+  encountered upon re-opening a previously-closed connection object. Thanks to
+  Alexander Bodnya for the report and David JM Emmett for the patch.
+- :feature:`-` Change the default configuration value for ``inline_ssh_env``
+  from ``False`` to ``True``, to better align with the practicalities of common
+  SSH server configurations.
+
+  .. warning::
+    This change is backwards incompatible if you were using
+    environment-variable-setting kwargs or config settings, such as
+    ``Connection.run(command, env={'SOME': 'ENV VARS'})``, and were not already
+    explicitly specifying the value of ``inline_ssh_env``.
+
+- :support:`-` Drop support for Python <3.6, including Python 2.
+
+  .. warning::
+    This is a backwards incompatible change if you are not yet on Python 3.6 or
+    above; however, pip shouldn't offer you this version of Fabric as long as
+    your pip version understands ``python_requires`` metadata.
+
 - :release:`2.7.1 <2022-07-14>`
 - :bug:`1924` (also :issue:`2007`) Overhaul behavior and testing re: merging
   together different sources for the ``key_filename`` parameter in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/sites/www/upgrading.rst 
new/fabric-3.0.1/sites/www/upgrading.rst
--- old/fabric-2.7.1/sites/www/upgrading.rst    2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/sites/www/upgrading.rst    2023-01-21 00:13:54.000000000 
+0100
@@ -36,7 +36,6 @@
     These are all listed in the rest of the doc too, so if you're already sold,
     just skip there.
 
-- Python 3 compatibility (specifically, we now support 2.7 and 3.4+);
 - Thread-safe - no more requirement on multiprocessing for concurrency;
 - API reorganized around `fabric.connection.Connection` objects instead of
   global module state;
@@ -195,7 +194,7 @@
         instead, then supply it to the ``connect_kwargs`` parameter. For
         example::
 
-            from io import StringIO  # or 'from StringIO' on Python 2
+            from io import StringIO
             from fabric.state import env
             from fabric2 import Connection
             from paramiko import RSAKey
@@ -282,9 +281,6 @@
 General / conceptual
 --------------------
 
-- Modern Fabric is fully Python 3 compatible; as a cost, Python 2.5 support (a
-  longstanding feature of Fabric 1) has been dropped - in fact, we've dropped
-  support for anything older than Python 2.7.
 - The CLI task-oriented workflow remains a primary design goal, but the library
   use case is no longer a second-class citizen; instead, the library
   functionality has been designed first, with the CLI/task features built on
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tasks.py new/fabric-3.0.1/tasks.py
--- old/fabric-2.7.1/tasks.py   2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/tasks.py   2023-01-21 00:13:54.000000000 +0100
@@ -1,4 +1,4 @@
-from os import environ, getcwd
+from os import getcwd
 import sys
 
 from invocations import ci
@@ -21,13 +21,6 @@
 
     Assumes Fabric 2+ is already installed as 'fabric2'.
     """
-    # This cannot, by definition, work under Python 3 as Fabric 1 is not Python
-    # 3 compatible.
-    # TODO: once the final Fabric 1 release is out w/ 3.x compat, fix this up
-    # and add to CI
-    PYTHON = environ.get("TRAVIS_PYTHON_VERSION", "")
-    if PYTHON.startswith("3") or PYTHON == "pypy3":
-        return
     c.run("pip install 'fabric<2'")
     # Make darn sure the two copies of fabric are coming from install root, not
     # local directory - which would result in 'fabric' always being v2!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/config.py 
new/fabric-3.0.1/tests/config.py
--- old/fabric-2.7.1/tests/config.py    2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/tests/config.py    2023-01-21 00:13:54.000000000 +0100
@@ -8,7 +8,7 @@
 from fabric import Config, Remote, RemoteShell
 from fabric.util import get_local_user
 
-from mock import patch, call
+from unittest.mock import patch, call
 
 from _util import support, faux_v1_env
 
@@ -47,7 +47,7 @@
         assert c.connect_kwargs == {}
         assert c.timeouts.connect is None
         assert c.ssh_config_path is None
-        assert c.inline_ssh_env is False
+        assert c.inline_ssh_env is True
 
     def overrides_some_Invoke_defaults(self):
         config = Config()
@@ -235,11 +235,12 @@
     def runtime_path_does_not_die_silently(self):
         try:
             Config(runtime_ssh_path="sure/thing/boss/whatever/you/say")
-        except IOError as e:
+        except FileNotFoundError as e:
             assert "No such file or directory" in str(e)
             assert e.errno == errno.ENOENT
+            assert e.filename == "sure/thing/boss/whatever/you/say"
         else:
-            assert False, "Bad runtime path didn't raise IOError!"
+            assert False, "Bad runtime path didn't raise error!"
 
     # TODO: skip on windows
     @patch.object(Config, "_load_ssh_file")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/conftest.py 
new/fabric-3.0.1/tests/conftest.py
--- old/fabric-2.7.1/tests/conftest.py  2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/conftest.py  2023-01-21 00:13:54.000000000 +0100
@@ -5,7 +5,7 @@
 
 from pytest import fixture
 
-from mock import patch
+from unittest.mock import patch
 
 
 # TODO: does this want to end up in the public fixtures module too?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/connection.py 
new/fabric-3.0.1/tests/connection.py
--- old/fabric-2.7.1/tests/connection.py        2022-07-15 00:37:01.000000000 
+0200
+++ new/fabric-3.0.1/tests/connection.py        2023-04-29 19:40:23.000000000 
+0200
@@ -1,16 +1,13 @@
 from itertools import chain, repeat
 
-try:
-    from invoke.vendor.six import b, StringIO
-except ImportError:
-    from six import b, StringIO
+from io import StringIO
 
 import errno
 from os.path import join
 import socket
 import time
 
-from mock import patch, Mock, call, ANY
+from unittest.mock import patch, Mock, call, ANY
 from paramiko.client import SSHClient, AutoAddPolicy
 from paramiko import SSHConfig
 import pytest  # for mark, internal raises
@@ -506,14 +503,16 @@
 
         class inline_ssh_env:
             def defaults_to_config_value(self):
-                assert Connection("host").inline_ssh_env is False
-                config = Config({"inline_ssh_env": True})
-                assert Connection("host", config=config).inline_ssh_env is True
+                assert Connection("host").inline_ssh_env is True
+                config = Config({"inline_ssh_env": False})
+                assert (
+                    Connection("host", config=config).inline_ssh_env is False
+                )
 
             def may_be_given(self):
-                assert Connection("host").inline_ssh_env is False
-                cxn = Connection("host", inline_ssh_env=True)
-                assert cxn.inline_ssh_env is True
+                assert Connection("host").inline_ssh_env is True
+                cxn = Connection("host", inline_ssh_env=False)
+                assert cxn.inline_ssh_env is False
 
     class from_v1:
         def setup(self):
@@ -546,11 +545,11 @@
                 cxn = Connection.from_v1(
                     self.env,
                     connect_kwargs={"foo": "bar"},
-                    inline_ssh_env=True,
+                    inline_ssh_env=False,
                     connect_timeout=15,
                 )
                 assert cxn.connect_kwargs["foo"] == "bar"
-                assert cxn.inline_ssh_env is True
+                assert cxn.inline_ssh_env is False
                 assert cxn.connect_timeout == 15
 
             def conflicting_kwargs_win_over_v1_env_values(self):
@@ -962,6 +961,24 @@
             c.close()
             client.close.assert_called_with()
 
+        def calls_SFTPClient_close(self, client):
+            "calls paramiko.SFTPClient.close()"
+            c = Connection("host")
+            c.open()
+            sftp_client = c.sftp()
+            assert c._sftp is not None
+            c.close()
+            assert c._sftp is None
+            sftp_client.close.assert_called_with()
+
+        def calls_SFTPClient_close_not_called_if_not_open(self, client):
+            "calls paramiko.SFTPClient.close()"
+            c = Connection("host")
+            c.open()
+            assert c._sftp is None
+            c.close()
+            assert c._sftp is None
+
         @patch("fabric.connection.AgentRequestHandler")
         def calls_agent_handler_close_if_enabled(self, Handler, client):
             c = Connection("host", forward_agent=True)
@@ -1013,9 +1030,9 @@
         @patch(remote_path)
         def passes_inline_env_to_Remote(self, Remote, client):
             Connection("host").run("command")
-            assert Remote.call_args[1]["inline_env"] is False
-            Connection("host", inline_ssh_env=True).run("command")
             assert Remote.call_args[1]["inline_env"] is True
+            Connection("host", inline_ssh_env=False).run("command")
+            assert Remote.call_args[1]["inline_env"] is False
 
         @patch(remote_path)
         def calls_Remote_run_with_command_and_kwargs_and_returns_its_result(
@@ -1029,7 +1046,7 @@
             # .assert_called_with()) stopped working, apparently triggered by
             # our code...somehow...after commit (roughly) 80906c7.
             # And yet, .call_args_list and its brethren work fine. Wha?
-            Remote.assert_any_call(context=c, inline_env=False)
+            Remote.assert_any_call(context=c, inline_env=True)
             remote.run.assert_has_calls(
                 [call("command"), call("command", warn=True, hide="stderr")]
             )
@@ -1120,9 +1137,9 @@
         @patch(remote_path)
         def passes_inline_env_to_Remote(self, Remote, client):
             Connection("host").sudo("command")
-            assert Remote.call_args[1]["inline_env"] is False
-            Connection("host", inline_ssh_env=True).sudo("command")
             assert Remote.call_args[1]["inline_env"] is True
+            Connection("host", inline_ssh_env=False).sudo("command")
+            assert Remote.call_args[1]["inline_env"] is False
 
         @patch(remote_path)
         def basic_invocation(self, Remote, client):
@@ -1136,7 +1153,7 @@
             # Remote.return_value is two different Mocks now, despite Remote's
             # own Mock having the same ID here and in code under test. WTF!!)
             expected = [
-                call(context=cxn, inline_env=False),
+                call(context=cxn, inline_env=True),
                 call().run(cmd, watchers=ANY),
             ]
             assert Remote.mock_calls == expected
@@ -1213,7 +1230,7 @@
             listener_sock = Mock(name="listener_sock")
             if listener_exception:
                 listener_sock.bind.side_effect = listener_exception
-            data = b("Some data")
+            data = "Some data".encode()
             tunnel_sock = Mock(name="tunnel_sock", recv=lambda n: data)
             local_addr = Mock()
             transport = client.get_transport.return_value
@@ -1224,6 +1241,7 @@
             # fire once & raise EAGAIN after)
             listener_sock.accept.side_effect = chain(
                 [(tunnel_sock, local_addr)],
+                # TODO: should this become BlockingIOError too?
                 repeat(socket.error(errno.EAGAIN, "nothing yet")),
             )
             obj = tunnel_sock if tunnel_exception is None else tunnel_exception
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/executor.py 
new/fabric-3.0.1/tests/executor.py
--- old/fabric-2.7.1/tests/executor.py  2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/executor.py  2023-01-21 00:13:54.000000000 +0100
@@ -4,7 +4,7 @@
 from fabric.executor import ConnectionCall
 from fabric.exceptions import NothingToDo
 
-from mock import Mock
+from unittest.mock import Mock
 from pytest import skip, raises  # noqa
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/group.py 
new/fabric-3.0.1/tests/group.py
--- old/fabric-2.7.1/tests/group.py     2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/group.py     2023-01-21 00:13:54.000000000 +0100
@@ -1,4 +1,4 @@
-from mock import Mock, patch, call
+from unittest.mock import Mock, patch, call
 from pytest import mark, raises
 
 from fabric import Connection, Group, SerialGroup, ThreadingGroup, GroupResult
@@ -222,9 +222,7 @@
             ("start", Thread.return_value.start.call_count),
             ("join", Thread.return_value.join.call_count),
         ):
-            err = (
-                "Expected {} calls to ExceptionHandlingThread.{}, got {}"
-            )  # noqa
+            err = "Expected {} calls to ExceptionHandlingThread.{}, got {}"  # 
noqa
             err = err.format(expected, name, got)
             assert expected, got == err
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/main.py 
new/fabric-3.0.1/tests/main.py
--- old/fabric-2.7.1/tests/main.py      2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/main.py      2023-04-29 19:40:23.000000000 +0200
@@ -8,7 +8,7 @@
 
 from invoke import run
 from invoke.util import cd
-from mock import patch
+from unittest.mock import patch
 import pytest  # because WHY would you expose @skip normally? -_-
 from pytest_relaxed import raises
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/runners.py 
new/fabric-3.0.1/tests/runners.py
--- old/fabric-2.7.1/tests/runners.py   2022-07-15 00:37:01.000000000 +0200
+++ new/fabric-3.0.1/tests/runners.py   2023-04-29 19:52:38.000000000 +0200
@@ -1,12 +1,9 @@
-try:
-    from invoke.vendor.six import StringIO
-except ImportError:
-    from six import StringIO
+from io import StringIO
 
-from mock import Mock, patch
+from unittest.mock import Mock, patch
 from pytest import skip  # noqa
 
-from invoke import pty_size, Result
+from invoke import pty_size, Result, Runner
 
 from fabric import Config, Connection, Remote, RemoteShell
 
@@ -93,6 +90,12 @@
             else:
                 assert False, "Runner failed to raise exception!"
 
+        def stop_calls_super_correctly(self, remote):
+            # RE: #2241
+            Runner.stop = Mock()
+            _runner().run(CMD)
+            Runner.stop.assert_called_once_with()
+
         def channel_close_skipped_when_channel_not_even_made(self):
             # I.e. if obtaining self.channel doesn't even happen (i.e. if
             # Connection.create_session() dies), we need to account for that
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/task.py 
new/fabric-3.0.1/tests/task.py
--- old/fabric-2.7.1/tests/task.py      2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/task.py      2023-01-21 00:13:54.000000000 +0100
@@ -1,6 +1,6 @@
 # NOTE: named task.py, not tasks.py, to avoid some occasional pytest weirdness
 
-from mock import Mock
+from unittest.mock import Mock
 from pytest import skip  # noqa
 
 import fabric
@@ -134,7 +134,5 @@
             )
             # TODO: worth using some subset of real Connection repr() in here?
             # For now, just stick with hostname.
-            expected = (
-                "<ConnectionCall '_dummy', args: (), kwargs: {}, host='host'>"
-            )  # noqa
+            expected = "<ConnectionCall '_dummy', args: (), kwargs: {}, 
host='host'>"  # noqa
             assert str(call) == expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/transfer.py 
new/fabric-3.0.1/tests/transfer.py
--- old/fabric-2.7.1/tests/transfer.py  2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/transfer.py  2023-01-21 00:13:54.000000000 +0100
@@ -1,9 +1,6 @@
-try:
-    from invoke.vendor.six import StringIO
-except ImportError:
-    from six import StringIO
+from io import StringIO
 
-from mock import Mock, call, patch
+from unittest.mock import Mock, call, patch
 from pytest_relaxed import raises
 from pytest import skip  # noqa
 from paramiko import SFTPAttributes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fabric-2.7.1/tests/util.py 
new/fabric-3.0.1/tests/util.py
--- old/fabric-2.7.1/tests/util.py      2021-12-05 00:24:42.000000000 +0100
+++ new/fabric-3.0.1/tests/util.py      2023-01-21 00:13:54.000000000 +0100
@@ -2,7 +2,7 @@
 Tests testing the fabric.util module, not utils for the tests!
 """
 
-from mock import patch
+from unittest.mock import patch
 
 from fabric.util import get_local_user
 

Reply via email to