summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Forcier <jeff@bitprophet.org>2017-06-09 12:44:38 -0700
committerJeff Forcier <jeff@bitprophet.org>2017-06-09 12:44:38 -0700
commite65ebf32562380db20946f2e4c3408fcbccefae7 (patch)
tree396a8387385fe2f27b92552d379cfaa8ee421013
parente25e1aacf511be00ee32636737f5574b84f50e4e (diff)
parent6d167ef832fa224a4c0c503b63d5cdba797bc251 (diff)
downloadparamiko-e65ebf32562380db20946f2e4c3408fcbccefae7.tar.gz
Merge branch '1.17' into 971-int
-rw-r--r--.travis.yml4
-rw-r--r--README.rst4
-rw-r--r--codecov.yml1
-rw-r--r--paramiko/client.py3
-rw-r--r--paramiko/resource.py71
-rw-r--r--paramiko/transport.py5
-rw-r--r--sites/www/changelog.rst7
-rw-r--r--tests/test_client.py21
8 files changed, 20 insertions, 96 deletions
diff --git a/.travis.yml b/.travis.yml
index ddff5e58..b5c2a245 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ install:
# Self-install for setup.py-driven deps
- pip install -e .
# Dev (doc/test running) requirements
- - pip install coveralls # For coveralls.io specifically
+ - pip install codecov # For codecov specifically
- pip install -r dev-requirements.txt
script:
# Main tests, w/ coverage!
@@ -33,4 +33,4 @@ notifications:
on_failure: change
email: false
after_success:
- - coveralls
+ - codecov
diff --git a/README.rst b/README.rst
index 1f7987e1..7bc3eeec 100644
--- a/README.rst
+++ b/README.rst
@@ -6,8 +6,8 @@ Paramiko
.. image:: https://travis-ci.org/paramiko/paramiko.svg?branch=master
:target: https://travis-ci.org/paramiko/paramiko
-.. image:: https://coveralls.io/repos/paramiko/paramiko/badge.svg?branch=master&service=github
- :target: https://coveralls.io/github/paramiko/paramiko?branch=master
+.. image:: https://codecov.io/gh/paramiko/paramiko/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/paramiko/paramiko
:Paramiko: Python SSH module
:Copyright: Copyright (c) 2003-2009 Robey Pointer <robeypointer@gmail.com>
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 00000000..69cb7601
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1 @@
+comment: false
diff --git a/paramiko/client.py b/paramiko/client.py
index 18139416..9612e165 100644
--- a/paramiko/client.py
+++ b/paramiko/client.py
@@ -34,7 +34,6 @@ from paramiko.dsskey import DSSKey
from paramiko.ecdsakey import ECDSAKey
from paramiko.hostkeys import HostKeys
from paramiko.py3compat import string_types
-from paramiko.resource import ResourceManager
from paramiko.rsakey import RSAKey
from paramiko.ssh_exception import (
SSHException, BadHostKeyException, NoValidConnectionsError
@@ -336,8 +335,6 @@ class SSHClient (ClosingContextManager):
if banner_timeout is not None:
t.banner_timeout = banner_timeout
t.start_client()
- t.set_sshclient(self)
- ResourceManager.register(self, t)
server_key = t.get_remote_server_key()
keytype = server_key.get_name()
diff --git a/paramiko/resource.py b/paramiko/resource.py
deleted file mode 100644
index 9809afbe..00000000
--- a/paramiko/resource.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
-#
-# This file is part of paramiko.
-#
-# Paramiko is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation; either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-
-"""
-Resource manager.
-"""
-
-import weakref
-
-
-class ResourceManager (object):
- """
- A registry of objects and resources that should be closed when those
- objects are deleted.
-
- This is meant to be a safer alternative to Python's ``__del__`` method,
- which can cause reference cycles to never be collected. Objects registered
- with the ResourceManager can be collected but still free resources when
- they die.
-
- Resources are registered using `register`, and when an object is garbage
- collected, each registered resource is closed by having its ``close()``
- method called. Multiple resources may be registered per object, but a
- resource will only be closed once, even if multiple objects register it.
- (The last object to register it wins.)
- """
-
- def __init__(self):
- self._table = {}
-
- def register(self, obj, resource):
- """
- Register a resource to be closed with an object is collected.
-
- When the given ``obj`` is garbage-collected by the Python interpreter,
- the ``resource`` will be closed by having its ``close()`` method called.
- Any exceptions are ignored.
-
- :param object obj: the object to track
- :param object resource:
- the resource to close when the object is collected
- """
- def callback(ref):
- try:
- resource.close()
- except:
- pass
- del self._table[id(resource)]
-
- # keep the weakref in a table so it sticks around long enough to get
- # its callback called. :)
- self._table[id(resource)] = weakref.ref(obj, callback)
-
-
-# singleton
-ResourceManager = ResourceManager()
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 21565673..1de6ff09 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -281,7 +281,6 @@ class Transport (threading.Thread, ClosingContextManager):
arguments.
"""
self.active = False
- self._sshclient = None
if isinstance(sock, string_types):
# convert "host:port" into (host, port)
@@ -637,9 +636,6 @@ class Transport (threading.Thread, ClosingContextManager):
Transport._modulus_pack = None
return False
- def set_sshclient(self, sshclient):
- self._sshclient = sshclient
-
def close(self):
"""
Close this session, and any open channels that are tied to it.
@@ -650,7 +646,6 @@ class Transport (threading.Thread, ClosingContextManager):
for chan in list(self._channels.values()):
chan._unlink()
self.sock.close()
- self._sshclient = None
def get_remote_server_key(self):
"""
diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst
index 59fbe6da..97f5884b 100644
--- a/sites/www/changelog.rst
+++ b/sites/www/changelog.rst
@@ -2,6 +2,13 @@
Changelog
=========
+* :support:`956 backported` Switch code coverage service from coveralls.io to
+ codecov.io (& then disable the latter's auto-comments.) Thanks to Nikolai
+ Røed Kristiansen for the patch.
+* :bug:`949` SSHClient and Transport could cause a memory leak if there's
+ a connection problem or protocol error, even if ``Transport.close()``
+ is called. Thanks Kyle Agronick for the discovery and investigation,
+ and Pierce Lopez for assistance.
* :release:`1.17.4 <2017-02-20>`
* :bug:`853 (1.17+)` Tweak how `RSAKey.__str__ <paramiko.rsakey.RSAKey>`
behaves so it doesn't cause ``TypeError`` under Python 3. Thanks to Francisco
diff --git a/tests/test_client.py b/tests/test_client.py
index 8411f64b..cbf51c8a 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -22,6 +22,8 @@ Some unit tests for SSHClient.
from __future__ import with_statement
+import gc
+import platform
import socket
from tempfile import mkstemp
import threading
@@ -277,12 +279,10 @@ class SSHClientTest (unittest.TestCase):
verify that when an SSHClient is collected, its transport (and the
transport's packetizer) is closed.
"""
- # Unclear why this is borked on Py3, but it is, and does not seem worth
- # pursuing at the moment.
- # XXX: It's the release of the references to e.g packetizer that fails
- # in py3...
- if not PY2:
+ # Skipped on PyPy because it fails on travis for unknown reasons
+ if platform.python_implementation() == "PyPy":
return
+
threading.Thread(target=self._run).start()
host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key'))
public_host_key = paramiko.RSAKey(data=host_key.asbytes())
@@ -301,14 +301,9 @@ class SSHClientTest (unittest.TestCase):
self.tc.close()
del self.tc
- # hrm, sometimes p isn't cleared right away. why is that?
- #st = time.time()
- #while (time.time() - st < 5.0) and (p() is not None):
- # time.sleep(0.1)
-
- # instead of dumbly waiting for the GC to collect, force a collection
- # to see whether the SSHClient object is deallocated correctly
- import gc
+ # 2 GCs are needed on PyPy, time is needed for Python 3
+ time.sleep(0.3)
+ gc.collect()
gc.collect()
self.assertTrue(p() is None)