Skip to content

Commit

Permalink
Merge pull request #111 from ploxiln/prep_2710
Browse files Browse the repository at this point in the history
prepare for release 2.7.10
  • Loading branch information
ploxiln authored Dec 1, 2021
2 parents 6263c8d + 20f82a1 commit e6be128
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 54 deletions.
2 changes: 1 addition & 1 deletion demos/rforward.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):
if chan is None:
continue
thr = threading.Thread(target=handler, args=(chan, remote_host, remote_port))
thr.setDaemon(True)
thr.daemon = True
thr.start()


Expand Down
2 changes: 1 addition & 1 deletion paramiko/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# last version component is odd for pre-release development, even for stable release
__version_info__ = (2, 7, 8)
__version_info__ = (2, 7, 10)
__version__ = '.'.join(map(str, __version_info__))
4 changes: 2 additions & 2 deletions paramiko/buffered_pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def feed(self, data):
if self._event is not None:
self._event.set()
self._buffer_frombytes(b(data))
self._cv.notifyAll()
self._cv.notify_all()
finally:
self._lock.release()

Expand Down Expand Up @@ -209,7 +209,7 @@ def close(self):
self._lock.acquire()
try:
self._closed = True
self._cv.notifyAll()
self._cv.notify_all()
if self._event is not None:
self._event.set()
finally:
Expand Down
4 changes: 2 additions & 2 deletions paramiko/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ def _window_adjust(self, m):
if self.ultra_debug:
self._log(DEBUG, 'window up {}'.format(nbytes))
self.out_window_size += nbytes
self.out_buffer_cv.notifyAll()
self.out_buffer_cv.notify_all()
finally:
self.lock.release()

Expand Down Expand Up @@ -1203,7 +1203,7 @@ def _set_closed(self):
self.closed = True
self.in_buffer.close()
self.in_stderr_buffer.close()
self.out_buffer_cv.notifyAll()
self.out_buffer_cv.notify_all()
# Notify any waiters that we are closed
self.event.set()
self.status_event.set()
Expand Down
31 changes: 12 additions & 19 deletions paramiko/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Common constants and global variables.
"""
import logging
from paramiko.py3compat import byte_chr, PY2, long, b
from paramiko.py3compat import byte_chr, PY2, long, text_type

MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG, \
MSG_SERVICE_REQUEST, MSG_SERVICE_ACCEPT = range(1, 7)
Expand Down Expand Up @@ -162,24 +162,17 @@


def asbytes(s):
"""
Coerce to bytes if possible or return unchanged.
"""
try:
# Attempt to run through our version of b(), which does the Right Thing
# for string/unicode/buffer (Py2) or bytes/str (Py3), and raises
# TypeError if it's not one of those types.
return b(s)
except TypeError:
try:
# If it wasn't a string/byte/buffer type object, try calling an
# asbytes() method, which many of our internal classes implement.
return s.asbytes()
except AttributeError:
# Finally, just do nothing & assume this object is sufficiently
# byte-y or buffer-y that everything will work out (or that callers
# are capable of handling whatever it is.)
return s
"""Coerce to bytes if possible or return unchanged."""
if isinstance(s, bytes):
return s
if isinstance(s, text_type):
# Accept text and encode as utf-8 for compatibility only.
return s.encode("utf-8")
asbytes = getattr(s, "asbytes", None)
if asbytes is not None:
return asbytes()
# May be an object that implements the buffer api, let callers handle.
return s


xffffffff = long(0xffffffff)
Expand Down
1 change: 1 addition & 0 deletions paramiko/hostkeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def __delitem__(self, key):
for e in list(self._entries):
if e.key.get_name() == key:
self._entries.remove(e)
break
else:
raise KeyError(key)

Expand Down
2 changes: 1 addition & 1 deletion paramiko/kex_gss.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def _parse_kexgss_complete(self, m):
hm.add_mpint(self.e)
hm.add_mpint(self.f)
hm.add_mpint(K)
H = sha1(str(hm)).digest()
H = sha1(hm.asbytes()).digest()
self.transport._set_K_H(K, H)
if srv_token is not None:
self.kexgss.ssh_init_sec_context(target=self.gss_host,
Expand Down
20 changes: 7 additions & 13 deletions paramiko/pkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,20 @@ def asbytes(self):
def __str__(self):
return self.asbytes()

# noinspection PyUnresolvedReferences
# TODO: The comparison functions should be removed as per:
# https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
def __cmp__(self, other):
# python-2 only, same purpose as __eq__()
return cmp(self.asbytes(), other.asbytes()) # noqa

def __eq__(self, other):
"""
Compare this key to another. Returns 0 if this key is equivalent to
the given key, or non-0 if they are different. Only the public parts
Compare this key to another. Returns True if this key is equivalent to
the given key, or False if they are different. Only the public parts
of the key are compared, so a public key will compare equal to its
corresponding private key.
:param .PKey other: key to compare to.
"""
hs = hash(self)
ho = hash(other)
if hs != ho:
return cmp(hs, ho) # noqa
return cmp(self.asbytes(), other.asbytes()) # noqa

def __eq__(self, other):
return hash(self) == hash(other)
return self.asbytes() == other.asbytes()

def get_name(self):
"""
Expand Down
11 changes: 8 additions & 3 deletions paramiko/rsakey.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,15 @@ def verify_ssh_sig(self, data, msg):
if isinstance(key, rsa.RSAPrivateKey):
key = key.public_key()

# pad received signature with leading zeros, key.verify() expects
# a signature of key_size bits (e.g. PuTTY doesn't pad)
sign = msg.get_binary()
diff = key.key_size - len(sign) * 8
if diff > 0:
sign = b"\x00" * ((diff + 7) // 8) + sign

try:
key.verify(
msg.get_binary(), data, padding.PKCS1v15(), hashes.SHA1()
)
key.verify(sign, data, padding.PKCS1v15(), hashes.SHA1())
except InvalidSignature:
return False
else:
Expand Down
2 changes: 1 addition & 1 deletion paramiko/sftp_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def _start_prefetch(self, chunks):
self._prefetch_done = False

t = threading.Thread(target=self._prefetch_thread, args=(chunks,))
t.setDaemon(True)
t.daemon = True
t.start()

def _prefetch_thread(self, chunks):
Expand Down
2 changes: 1 addition & 1 deletion paramiko/ssh_gss.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ def ssh_init_sec_context(self, target, desired_mech=None,
error, token = self._gss_ctxt.authorize(recv_token)
token = token[0].Buffer
except pywintypes.error as e:
e.strerror += ", Target: {}".format(e, self._gss_host)
e.strerror += ", Target: {}".format(self._gss_host)
raise

if error == 0:
Expand Down
2 changes: 1 addition & 1 deletion paramiko/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ def __init__(self,

# okay, normal socket-ish flow here...
threading.Thread.__init__(self)
self.setDaemon(True)
self.daemon = True
self.sock = sock
# we set the timeout so we can check self.active periodically to
# see if we should bail. socket.timeout exception is never propagated.
Expand Down
2 changes: 1 addition & 1 deletion paramiko/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def mod_inverse(x, m):

def get_thread_id():
global _g_thread_ids, _g_thread_counter, _g_thread_lock
tid = id(threading.currentThread())
tid = id(threading.current_thread())
try:
return _g_thread_ids[tid]
except KeyError:
Expand Down
2 changes: 1 addition & 1 deletion tests/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __feed(self, data):
self.__lock.acquire()
try:
self.__in_buffer += data
self.__cv.notifyAll()
self.__cv.notify_all()
finally:
self.__lock.release()

Expand Down
15 changes: 10 additions & 5 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,17 @@ def test_cleanup(self):
self.tc.close()
del self.tc

# force a collection to see whether the SSHClient object is deallocated
# 2 GCs are needed on PyPy, time is needed for Python 3
time.sleep(0.3)
# GC is unpredictable, depending on python version and implementation
time.sleep(0.1)
gc.collect()
time.sleep(0.2)
gc.collect()
time.sleep(0.1)
gc.collect()
time.sleep(0.2)
gc.collect()
time.sleep(0.1)
gc.collect()

self.assertTrue(p() is None)

def test_client_can_be_used_as_context_manager(self):
Expand Down Expand Up @@ -596,7 +601,7 @@ def _setup_for_env(self):
self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion')

self.event.wait(1.0)
self.assertTrue(self.event.isSet())
self.assertTrue(self.event.is_set())
self.assertTrue(self.ts.is_active())

def test_update_environment(self):
Expand Down
17 changes: 17 additions & 0 deletions tests/test_hostkeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,20 @@ def test_delitem(self):
pass # Good
else:
assert False, "Entry was not deleted from HostKeys on delitem!"

def test_entry_delitem(self):
hostdict = paramiko.HostKeys('hostfile.temp')
target = 'happy.example.com'
entry = hostdict[target]
key_type_list = [key_type for key_type in entry]
for key_type in key_type_list:
del entry[key_type]

# will KeyError if not present
for key_type in key_type_list:
try:
del entry[key_type]
except KeyError:
pass # Good
else:
assert False, "Key was not deleted from Entry on delitem!"
4 changes: 2 additions & 2 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ def test_rekey_deadlock(self):
class SendThread(threading.Thread):
def __init__(self, chan, iterations, done_event):
threading.Thread.__init__(self, None, None, self.__class__.__name__)
self.setDaemon(True)
self.daemon = True
self.chan = chan
self.iterations = iterations
self.done_event = done_event
Expand All @@ -738,7 +738,7 @@ def run(self):
class ReceiveThread(threading.Thread):
def __init__(self, chan, done_event):
threading.Thread.__init__(self, None, None, self.__class__.__name__)
self.setDaemon(True)
self.daemon = True
self.chan = chan
self.done_event = done_event
self.watchdog_event = threading.Event()
Expand Down

0 comments on commit e6be128

Please sign in to comment.