diff options
author | Jeff Forcier <jeff@bitprophet.org> | 2017-06-09 12:44:38 -0700 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2017-06-09 12:44:38 -0700 |
commit | e65ebf32562380db20946f2e4c3408fcbccefae7 (patch) | |
tree | 396a8387385fe2f27b92552d379cfaa8ee421013 | |
parent | e25e1aacf511be00ee32636737f5574b84f50e4e (diff) | |
parent | 6d167ef832fa224a4c0c503b63d5cdba797bc251 (diff) | |
download | paramiko-e65ebf32562380db20946f2e4c3408fcbccefae7.tar.gz |
Merge branch '1.17' into 971-int
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | README.rst | 4 | ||||
-rw-r--r-- | codecov.yml | 1 | ||||
-rw-r--r-- | paramiko/client.py | 3 | ||||
-rw-r--r-- | paramiko/resource.py | 71 | ||||
-rw-r--r-- | paramiko/transport.py | 5 | ||||
-rw-r--r-- | sites/www/changelog.rst | 7 | ||||
-rw-r--r-- | tests/test_client.py | 21 |
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 @@ -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) |