aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--paramiko/__init__.py2
-rw-r--r--paramiko/channel.py14
-rw-r--r--paramiko/config.py12
-rw-r--r--paramiko/hostkeys.py2
-rw-r--r--paramiko/py3compat.py4
-rw-r--r--paramiko/sftp_client.py14
-rw-r--r--paramiko/transport.py3
-rw-r--r--setup.py2
-rw-r--r--sites/www/changelog.rst27
-rwxr-xr-xtests/test_file.py10
-rw-r--r--tests/test_util.py6
12 files changed, 73 insertions, 25 deletions
diff --git a/README b/README
index 9305bfb..61c5c85 100644
--- a/README
+++ b/README
@@ -35,7 +35,7 @@ Requirements
------------
- Python 2.6 or better <http://www.python.org/> - this includes Python
- 3.3 and higher as well.
+ 3.2 and higher as well.
- pycrypto 2.1 or better <https://www.dlitz.net/software/pycrypto/>
- ecdsa 0.9 or better <https://pypi.python.org/pypi/ecdsa>
diff --git a/paramiko/__init__.py b/paramiko/__init__.py
index 4c62ad4..2ebc8a6 100644
--- a/paramiko/__init__.py
+++ b/paramiko/__init__.py
@@ -23,7 +23,7 @@ if sys.version_info < (2, 6):
__author__ = "Jeff Forcier <jeff@bitprophet.org>"
-__version__ = "1.14.0"
+__version__ = "1.14.1"
__version_info__ = tuple([ int(d) for d in __version__.split(".") ])
__license__ = "GNU Lesser General Public License (LGPL)"
diff --git a/paramiko/channel.py b/paramiko/channel.py
index 583809d..49d8dd6 100644
--- a/paramiko/channel.py
+++ b/paramiko/channel.py
@@ -280,7 +280,7 @@ class Channel (object):
def recv_exit_status(self):
"""
Return the exit status from the process on the server. This is
- mostly useful for retrieving the reults of an `exec_command`.
+ mostly useful for retrieving the results of an `exec_command`.
If the command hasn't finished yet, this method will wait until
it does, or until the channel is closed. If no exit status is
provided by the server, -1 is returned.
@@ -330,7 +330,7 @@ class Channel (object):
If you omit the auth_cookie, a new secure random 128-bit value will be
generated, used, and returned. You will need to use this value to
verify incoming x11 requests and replace them with the actual local
- x11 cookie (which requires some knoweldge of the x11 protocol).
+ x11 cookie (which requires some knowledge of the x11 protocol).
If a handler is passed in, the handler is called from another thread
whenever a new x11 connection arrives. The default handler queues up
@@ -339,7 +339,7 @@ class Channel (object):
handler(channel: Channel, (address: str, port: int))
- :param int screen_number: the x11 screen number (0, 10, etc)
+ :param int screen_number: the x11 screen number (0, 10, etc.)
:param str auth_protocol:
the name of the X11 authentication method used; if none is given,
``"MIT-MAGIC-COOKIE-1"`` is used
@@ -744,10 +744,10 @@ class Channel (object):
:raises socket.timeout:
if sending stalled for longer than the timeout set by `settimeout`.
:raises socket.error:
- if an error occured before the entire string was sent.
+ if an error occurred before the entire string was sent.
.. note::
- If the channel is closed while only part of the data hase been
+ If the channel is closed while only part of the data has been
sent, there is no way to determine how much data (if any) was sent.
This is irritating, but identically follows Python's API.
"""
@@ -771,7 +771,7 @@ class Channel (object):
:raises socket.timeout:
if sending stalled for longer than the timeout set by `settimeout`.
:raises socket.error:
- if an error occured before the entire string was sent.
+ if an error occurred before the entire string was sent.
.. versionadded:: 1.1
"""
@@ -812,7 +812,7 @@ class Channel (object):
def fileno(self):
"""
Returns an OS-level file descriptor which can be used for polling, but
- but not for reading or writing. This is primaily to allow Python's
+ but not for reading or writing. This is primarily to allow Python's
``select`` module to work.
The first time ``fileno`` is called on a channel, a pipe is created to
diff --git a/paramiko/config.py b/paramiko/config.py
index 77fa13d..96ec9ef 100644
--- a/paramiko/config.py
+++ b/paramiko/config.py
@@ -55,7 +55,7 @@ class SSHConfig (object):
"""
host = {"host": ['*'], "config": {}}
for line in file_obj:
- line = line.rstrip('\n').lstrip()
+ line = line.rstrip('\r\n').lstrip()
if (line == '') or (line[0] == '#'):
continue
if '=' in line:
@@ -83,7 +83,7 @@ class SSHConfig (object):
#identityfile, localforward, remoteforward keys are special cases, since they are allowed to be
# specified multiple times and they should be tried in order
# of specification.
-
+
elif key in ['identityfile', 'localforward', 'remoteforward']:
if key in host['config']:
host['config'][key].append(value)
@@ -200,10 +200,12 @@ class SSHConfig (object):
for find, replace in replacements[k]:
if isinstance(config[k], list):
for item in range(len(config[k])):
- config[k][item] = config[k][item].\
- replace(find, str(replace))
+ if find in config[k][item]:
+ config[k][item] = config[k][item].\
+ replace(find, str(replace))
else:
- config[k] = config[k].replace(find, str(replace))
+ if find in config[k]:
+ config[k] = config[k].replace(find, str(replace))
return config
diff --git a/paramiko/hostkeys.py b/paramiko/hostkeys.py
index c0caeda..cd65e77 100644
--- a/paramiko/hostkeys.py
+++ b/paramiko/hostkeys.py
@@ -179,7 +179,7 @@ class HostKeys (MutableMapping):
entries = []
for e in self._entries:
for h in e.hostnames:
- if h.startswith('|1|') and constant_time_bytes_eq(self.hash_host(hostname, h), h) or h == hostname:
+ if h.startswith('|1|') and not hostname.startswith('|1|') and constant_time_bytes_eq(self.hash_host(hostname, h), h) or h == hostname:
entries.append(e)
if len(entries) == 0:
return None
diff --git a/paramiko/py3compat.py b/paramiko/py3compat.py
index 8842b98..57c096b 100644
--- a/paramiko/py3compat.py
+++ b/paramiko/py3compat.py
@@ -39,6 +39,8 @@ if PY2:
return s
elif isinstance(s, unicode):
return s.encode(encoding)
+ elif isinstance(s, buffer):
+ return s
else:
raise TypeError("Expected unicode or bytes, got %r" % s)
@@ -49,6 +51,8 @@ if PY2:
return s.decode(encoding)
elif isinstance(s, unicode):
return s
+ elif isinstance(s, buffer):
+ return s.decode(encoding)
else:
raise TypeError("Expected unicode or bytes, got %r" % s)
diff --git a/paramiko/sftp_client.py b/paramiko/sftp_client.py
index 1caaf16..99a29e3 100644
--- a/paramiko/sftp_client.py
+++ b/paramiko/sftp_client.py
@@ -534,9 +534,7 @@ class SFTPClient(BaseSFTP):
an `.SFTPAttributes` object containing attributes about the given
file.
- .. versionadded:: 1.4
- .. versionchanged:: 1.7.4
- Began returning rich attribute objects.
+ .. versionadded:: 1.10
"""
with self.file(remotepath, 'wb') as fr:
fr.set_pipelined(True)
@@ -566,7 +564,9 @@ class SFTPClient(BaseSFTP):
The SFTP operations use pipelining for speed.
:param str localpath: the local file to copy
- :param str remotepath: the destination path on the SFTP server
+ :param str remotepath: the destination path on the SFTP server. Note
+ that the filename should be included. Only specifying a directory
+ may result in an error.
:param callable callback:
optional callback function (form: ``func(int, int)``) that accepts
the bytes transferred so far and the total bytes to be transferred
@@ -584,7 +584,7 @@ class SFTPClient(BaseSFTP):
"""
file_size = os.stat(localpath).st_size
with open(localpath, 'rb') as fl:
- return self.putfo(fl, remotepath, os.stat(localpath).st_size, callback, confirm)
+ return self.putfo(fl, remotepath, file_size, callback, confirm)
def getfo(self, remotepath, fl, callback=None):
"""
@@ -601,9 +601,7 @@ class SFTPClient(BaseSFTP):
the bytes transferred so far and the total bytes to be transferred
:return: the `number <int>` of bytes written to the opened file object
- .. versionadded:: 1.4
- .. versionchanged:: 1.7.4
- Added the ``callable`` param.
+ .. versionadded:: 1.10
"""
with self.open(remotepath, 'rb') as fr:
file_size = self.stat(remotepath).st_size
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 406626a..1a33e1a 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -164,6 +164,8 @@ class Transport (threading.Thread):
:param socket sock:
a socket or socket-like object to create the session over.
"""
+ self.active = False
+
if isinstance(sock, string_types):
# convert "host:port" into (host, port)
hl = sock.split(':', 1)
@@ -219,7 +221,6 @@ class Transport (threading.Thread):
self.H = None
self.K = None
- self.active = False
self.initial_kex_done = False
self.in_kex = False
self.authenticated = False
diff --git a/setup.py b/setup.py
index c0f1e57..38e444f 100644
--- a/setup.py
+++ b/setup.py
@@ -56,7 +56,7 @@ if sys.platform == 'darwin':
setup(
name = "paramiko",
- version = "1.14.0",
+ version = "1.14.1",
description = "SSH2 protocol library",
long_description = longdesc,
author = "Jeff Forcier",
diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst
index f8a4d2c..0fcde10 100644
--- a/sites/www/changelog.rst
+++ b/sites/www/changelog.rst
@@ -2,6 +2,33 @@
Changelog
=========
+* :release:`1.14.1 <2014-08-25>`
+* :release:`1.13.2 <2014-08-25>`
+* :bug:`376` Be less aggressive about expanding variables in ``ssh_config``
+ files, which results in a speedup of SSH config parsing. Credit to Olle
+ Lundberg.
+* :support:`324 backported` A bevvy of documentation typo fixes, courtesy of Roy
+ Wellington.
+* :bug:`312` `paramiko.transport.Transport` had a bug in its ``__repr__`` which
+ surfaces during errors encountered within its ``__init__``, causing
+ problematic tracebacks in such situations. Thanks to Simon Percivall for
+ catch & patch.
+* :bug:`272` Fix a bug where ``known_hosts`` parsing hashed the input hostname
+ as well as the hostnames from the ``known_hosts`` file, on every comparison.
+ Thanks to ``@sigmunau`` for final patch and ``@ostacey`` for the original
+ report.
+* :bug:`239` Add Windows-style CRLF support to SSH config file parsing. Props
+ to Christopher Swenson.
+* :support:`229` Fix a couple of incorrectly-copied docstrings' ``..
+ versionadded::`` RST directives. Thanks to Aarni Koskela for the catch.
+* :support:`169 backported` Minor refactor of
+ `paramiko.sftp_client.SFTPClient.put` thanks to Abhinav Upadhyay.
+* :bug:`285` (also :issue:`352`) Update our Python 3 ``b()`` compatibility shim
+ to handle ``buffer`` objects correctly; this fixes a frequently reported
+ issue affecting many users, including users of the ``bzr`` software suite.
+ Thanks to ``@basictheprogram`` for the initial report, Jelmer Vernooij for
+ the fix and Andrew Starr-Bochicchio & Jeremy T. Bouse (among others) for
+ discussion & feedback.
* :release:`1.14.0 <2014-05-07>`
* :release:`1.13.1 <2014-05-07>`
* :release:`1.12.4 <2014-05-07>`
diff --git a/tests/test_file.py b/tests/test_file.py
index c6edd7a..22a34ac 100755
--- a/tests/test_file.py
+++ b/tests/test_file.py
@@ -23,6 +23,7 @@ Some unit tests for the BufferedFile abstraction.
import unittest
from paramiko.file import BufferedFile
from paramiko.common import linefeed_byte, crlf, cr_byte
+import sys
class LoopbackFile (BufferedFile):
@@ -151,6 +152,15 @@ class BufferedFileTest (unittest.TestCase):
b'need to close them again.\n')
f.close()
+ def test_8_buffering(self):
+ """
+ verify that buffered objects can be written
+ """
+ if sys.version_info[0] == 2:
+ f = LoopbackFile('r+', 16)
+ f.write(buffer(b'Too small.'))
+ f.close()
+
if __name__ == '__main__':
from unittest import main
main()
diff --git a/tests/test_util.py b/tests/test_util.py
index 69c7551..44fb8ab 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -333,3 +333,9 @@ IdentityFile something_%l_using_fqdn
"""
config = paramiko.util.parse_ssh_config(StringIO(test_config))
assert config.lookup('meh') # will die during lookup() if bug regresses
+
+ def test_13_config_dos_crlf_succeeds(self):
+ config_file = StringIO("host abcqwerty\r\nHostName 127.0.0.1\r\n")
+ config = paramiko.SSHConfig()
+ config.parse(config_file)
+ self.assertEqual(config.lookup("abcqwerty")["hostname"], "127.0.0.1")