From a7fdf17501e4d9732eed164f023886b01f934478 Mon Sep 17 00:00:00 2001
From: Pan <zuboci@yandex.com>
Date: Tue, 29 May 2018 22:14:49 +0100
Subject: [PATCH] Updates for latest ssh2-python release. Added agent
 forwarding compile time flag.

---
 Changelog.rst                        |  15 +-
 pssh/clients/native/single.py        |  27 +-
 pssh/native/_ssh2.c                  | 926 ++++++++++++++++-----------
 pssh/native/_ssh2.pyx                |   6 +-
 setup.py                             |   8 +-
 tests/base_ssh2_test.py              |   2 +-
 tests/test_native_parallel_client.py |   9 +-
 tests/test_native_single_client.py   |   2 +-
 8 files changed, 589 insertions(+), 406 deletions(-)

diff --git a/Changelog.rst b/Changelog.rst
index 04f26ef5..70af87b2 100644
--- a/Changelog.rst
+++ b/Changelog.rst
@@ -1,13 +1,26 @@
 Change Log
 ============
 
+1.6.3
+++++++
+
+Changes
+--------
+
+* Re-generated C code with latest Cython release.
+
+Fixes
+------
+
+* ``ssh2-python`` >= 0.14.0 support.
+
 1.6.2
 ++++++
 
 Fixes
 ------
 
-* Native client proxy initilisation failures were not caught by ``stop_on_errors=False`` - #121.
+* Native client proxy initialisation failures were not caught by ``stop_on_errors=False`` - #121.
 
 1.6.1
 +++++++
diff --git a/pssh/clients/native/single.py b/pssh/clients/native/single.py
index 3ee46cd2..a021bb11 100644
--- a/pssh/clients/native/single.py
+++ b/pssh/clients/native/single.py
@@ -28,8 +28,7 @@
 from gevent import sleep, socket, get_hub
 from gevent.hub import Hub
 from ssh2.error_codes import LIBSSH2_ERROR_EAGAIN
-from ssh2.exceptions import SFTPHandleError, \
-    SFTPIOError as SFTPIOError_ssh2
+from ssh2.exceptions import SFTPHandleError, SFTPProtocolError
 from ssh2.session import Session
 from ssh2.sftp import LIBSSH2_FXF_READ, LIBSSH2_FXF_CREAT, LIBSSH2_FXF_WRITE, \
     LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR, LIBSSH2_SFTP_S_IRGRP, \
@@ -416,18 +415,12 @@ def _make_sftp(self):
             sftp = self.session.sftp_init()
         except Exception as ex:
             raise SFTPError(ex)
-        errno = self.session.last_errno()
-        while (sftp is None and errno == LIBSSH2_ERROR_EAGAIN) \
-                or sftp == LIBSSH2_ERROR_EAGAIN:
+        while sftp == LIBSSH2_ERROR_EAGAIN:
             wait_select(self.session)
             try:
                 sftp = self.session.sftp_init()
             except Exception as ex:
                 raise SFTPError(ex)
-            errno = self.session.last_errno()
-        if sftp is None and errno != LIBSSH2_ERROR_EAGAIN:
-            raise SFTPError("Error initialising SFTP - error code %s",
-                            errno)
         return sftp
 
     def _mkdir(self, sftp, directory):
@@ -449,7 +442,7 @@ def _mkdir(self, sftp, directory):
             LIBSSH2_SFTP_S_IXOTH
         try:
             self._eagain(sftp.mkdir, directory, mode)
-        except SFTPIOError_ssh2 as error:
+        except SFTPProtocolError as error:
             msg = "Error occured creating directory %s on host %s - %s"
             logger.error(msg, directory, self.host, error)
             raise SFTPIOError(msg, directory, self.host, error)
@@ -485,7 +478,7 @@ def copy_file(self, local_file, remote_file, recurse=False,
         if destination is not None:
             try:
                 self._eagain(sftp.stat, destination)
-            except SFTPHandleError:
+            except (SFTPHandleError, SFTPProtocolError):
                 self.mkdir(sftp, destination)
         self.sftp_put(sftp, local_file, remote_file)
         logger.info("Copied local file %s to remote destination %s:%s",
@@ -508,7 +501,7 @@ def sftp_put(self, sftp, local_file, remote_file):
                 self._sftp_put(remote_fh, local_file)
                 # THREAD_POOL.apply(
                 #     sftp_put, args=(self.session, remote_fh, local_file))
-            except SFTPIOError_ssh2 as ex:
+            except SFTPProtocolError as ex:
                 msg = "Error writing to remote file %s - %s"
                 logger.error(msg, remote_file, ex)
                 raise SFTPIOError(msg, remote_file, ex)
@@ -539,7 +532,7 @@ def mkdir(self, sftp, directory, _parent_path=None):
             _dir = '/'.join((_parent_path, _dir))
         try:
             self._eagain(sftp.stat, _dir)
-        except SFTPHandleError as ex:
+        except (SFTPHandleError, SFTPProtocolError) as ex:
             logger.debug("Stat for %s failed with %s", _dir, ex)
             self._mkdir(sftp, _dir)
         if sub_dirs is not None:
@@ -582,7 +575,7 @@ def copy_remote_file(self, remote_file, local_file, recurse=False,
         sftp = self._make_sftp() if sftp is None else sftp
         try:
             self._eagain(sftp.stat, remote_file)
-        except SFTPHandleError:
+        except (SFTPHandleError, SFTPProtocolError):
             msg = "Remote file or directory %s does not exist"
             logger.error(msg, remote_file)
             raise SFTPIOError(msg, remote_file)
@@ -635,7 +628,7 @@ def scp_recv(self, remote_file, local_file, recurse=False, sftp=None,
         if recurse:
             try:
                 self._eagain(sftp.stat, remote_file)
-            except SFTPHandleError:
+            except (SFTPHandleError, SFTPProtocolError):
                 msg = "Remote file or directory %s does not exist"
                 logger.error(msg, remote_file)
                 raise SCPError(msg, remote_file)
@@ -744,7 +737,7 @@ def scp_send(self, local_file, remote_file, recurse=False, sftp=None):
             sftp = self._make_sftp() if sftp is None else sftp
             try:
                 self._eagain(sftp.stat, destination)
-            except SFTPHandleError:
+            except (SFTPHandleError, SFTPProtocolError):
                 self.mkdir(sftp, destination)
         self._scp_send(local_file, remote_file)
         logger.info("SCP local file %s to remote destination %s:%s",
@@ -807,7 +800,7 @@ def sftp_get(self, sftp, remote_file, local_file):
                 # cannot be used simultaneously in multiple threads.
                 # THREAD_POOL.apply(
                 #     sftp_get, args=(self.session, remote_fh, local_file))
-            except SFTPIOError_ssh2 as ex:
+            except SFTPProtocolError as ex:
                 msg = "Error reading from remote file %s - %s"
                 logger.error(msg, remote_file, ex)
                 raise SFTPIOError(msg, remote_file, ex)
diff --git a/pssh/native/_ssh2.c b/pssh/native/_ssh2.c
index 3f2fea39..f398cc3f 100644
--- a/pssh/native/_ssh2.c
+++ b/pssh/native/_ssh2.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.27.3 */
+/* Generated by Cython 0.28.3 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -7,7 +7,7 @@
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)
     #error Cython requires Python 2.6+ or Python 3.3+.
 #else
-#define CYTHON_ABI "0_27_3"
+#define CYTHON_ABI "0_28_3"
 #define CYTHON_FUTURE_DIVISION 0
 #include <stddef.h>
 #ifndef offsetof
@@ -183,6 +183,103 @@
   #undef BASE
   #undef MASK
 #endif
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#ifndef __has_cpp_attribute
+  #define __has_cpp_attribute(x) 0
+#endif
+#ifndef CYTHON_RESTRICT
+  #if defined(__GNUC__)
+    #define CYTHON_RESTRICT __restrict__
+  #elif defined(_MSC_VER) && _MSC_VER >= 1400
+    #define CYTHON_RESTRICT __restrict
+  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    #define CYTHON_RESTRICT restrict
+  #else
+    #define CYTHON_RESTRICT
+  #endif
+#endif
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define CYTHON_UNUSED __attribute__ ((__unused__))
+#   else
+#     define CYTHON_UNUSED
+#   endif
+# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
+#   define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+#   define CYTHON_UNUSED
+# endif
+#endif
+#ifndef CYTHON_MAYBE_UNUSED_VAR
+#  if defined(__cplusplus)
+     template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
+#  else
+#    define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
+#  endif
+#endif
+#ifndef CYTHON_NCP_UNUSED
+# if CYTHON_COMPILING_IN_CPYTHON
+#  define CYTHON_NCP_UNUSED
+# else
+#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
+# endif
+#endif
+#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
+#ifdef _MSC_VER
+    #ifndef _MSC_STDINT_H_
+        #if _MSC_VER < 1300
+           typedef unsigned char     uint8_t;
+           typedef unsigned int      uint32_t;
+        #else
+           typedef unsigned __int8   uint8_t;
+           typedef unsigned __int32  uint32_t;
+        #endif
+    #endif
+#else
+   #include <stdint.h>
+#endif
+#ifndef CYTHON_FALLTHROUGH
+  #if defined(__cplusplus) && __cplusplus >= 201103L
+    #if __has_cpp_attribute(fallthrough)
+      #define CYTHON_FALLTHROUGH [[fallthrough]]
+    #elif __has_cpp_attribute(clang::fallthrough)
+      #define CYTHON_FALLTHROUGH [[clang::fallthrough]]
+    #elif __has_cpp_attribute(gnu::fallthrough)
+      #define CYTHON_FALLTHROUGH [[gnu::fallthrough]]
+    #endif
+  #endif
+  #ifndef CYTHON_FALLTHROUGH
+    #if __has_attribute(fallthrough)
+      #define CYTHON_FALLTHROUGH __attribute__((fallthrough))
+    #else
+      #define CYTHON_FALLTHROUGH
+    #endif
+  #endif
+  #if defined(__clang__ ) && defined(__apple_build_version__)
+    #if __apple_build_version__ < 7000000
+      #undef  CYTHON_FALLTHROUGH
+      #define CYTHON_FALLTHROUGH
+    #endif
+  #endif
+#endif
+
+#ifndef CYTHON_INLINE
+  #if defined(__clang__)
+    #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
+  #elif defined(__GNUC__)
+    #define CYTHON_INLINE __inline__
+  #elif defined(_MSC_VER)
+    #define CYTHON_INLINE __inline
+  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    #define CYTHON_INLINE inline
+  #else
+    #define CYTHON_INLINE
+  #endif
+#endif
+
 #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
   #define Py_OptimizeFlag 0
 #endif
@@ -211,12 +308,12 @@
 #ifndef Py_TPFLAGS_HAVE_FINALIZE
   #define Py_TPFLAGS_HAVE_FINALIZE 0
 #endif
-#if PY_VERSION_HEX < 0x030700A0 || !defined(METH_FASTCALL)
+#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL)
   #ifndef METH_FASTCALL
      #define METH_FASTCALL 0x80
   #endif
-  typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args, Py_ssize_t nargs);
-  typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject **args,
+  typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs);
+  typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args,
                                                           Py_ssize_t nargs, PyObject *kwnames);
 #else
   #define __Pyx_PyCFunctionFast _PyCFunctionFast
@@ -228,6 +325,18 @@
 #else
 #define __Pyx_PyFastCFunction_Check(func) 0
 #endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
+  #define PyObject_Malloc(s)   PyMem_Malloc(s)
+  #define PyObject_Free(p)     PyMem_Free(p)
+  #define PyObject_Realloc(p)  PyMem_Realloc(p)
+#endif
+#if CYTHON_COMPILING_IN_PYSTON
+  #define __Pyx_PyCode_HasFreeVars(co)  PyCode_HasFreeVars(co)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
+#else
+  #define __Pyx_PyCode_HasFreeVars(co)  (PyCode_GetNumFree(co) > 0)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno)  (frame)->f_lineno = (lineno)
+#endif
 #if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000
   #define __Pyx_PyThreadState_Current PyThreadState_GET()
 #elif PY_VERSION_HEX >= 0x03060000
@@ -237,6 +346,36 @@
 #else
   #define __Pyx_PyThreadState_Current _PyThreadState_Current
 #endif
+#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT)
+#include "pythread.h"
+#define Py_tss_NEEDS_INIT 0
+typedef int Py_tss_t;
+static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) {
+  *key = PyThread_create_key();
+  return 0; // PyThread_create_key reports success always
+}
+static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) {
+  Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t));
+  *key = Py_tss_NEEDS_INIT;
+  return key;
+}
+static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) {
+  PyObject_Free(key);
+}
+static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) {
+  return *key != Py_tss_NEEDS_INIT;
+}
+static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) {
+  PyThread_delete_key(*key);
+  *key = Py_tss_NEEDS_INIT;
+}
+static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) {
+  return PyThread_set_key_value(*key, value);
+}
+static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
+  return PyThread_get_key_value(*key);
+}
+#endif // TSS (Thread Specific Storage) API
 #if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized)
 #define __Pyx_PyDict_NewPresized(n)  ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n))
 #else
@@ -249,6 +388,11 @@
   #define __Pyx_PyNumber_Divide(x,y)         PyNumber_Divide(x,y)
   #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceDivide(x,y)
 #endif
+#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS
+#define __Pyx_PyDict_GetItemStr(dict, name)  _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash)
+#else
+#define __Pyx_PyDict_GetItemStr(dict, name)  PyDict_GetItem(dict, name)
+#endif
 #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
   #define CYTHON_PEP393_ENABLED 1
   #define __Pyx_PyUnicode_READY(op)       (likely(PyUnicode_IS_READY(op)) ?\
@@ -293,18 +437,6 @@
 #if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
   #define PyObject_Format(obj, fmt)  PyObject_CallMethod(obj, "__format__", "O", fmt)
 #endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
-  #define PyObject_Malloc(s)   PyMem_Malloc(s)
-  #define PyObject_Free(p)     PyMem_Free(p)
-  #define PyObject_Realloc(p)  PyMem_Realloc(p)
-#endif
-#if CYTHON_COMPILING_IN_PYSTON
-  #define __Pyx_PyCode_HasFreeVars(co)  PyCode_HasFreeVars(co)
-  #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
-#else
-  #define __Pyx_PyCode_HasFreeVars(co)  (PyCode_GetNumFree(co) > 0)
-  #define __Pyx_PyFrame_SetLineNumber(frame, lineno)  (frame)->f_lineno = (lineno)
-#endif
 #define __Pyx_PyString_FormatSafe(a, b)   ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
 #define __Pyx_PyUnicode_FormatSafe(a, b)  ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
 #if PY_MAJOR_VERSION >= 3
@@ -321,6 +453,7 @@
   #define PyString_Type                PyUnicode_Type
   #define PyString_Check               PyUnicode_Check
   #define PyString_CheckExact          PyUnicode_CheckExact
+  #define PyObject_Unicode             PyObject_Str
 #endif
 #if PY_MAJOR_VERSION >= 3
   #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj)
@@ -332,7 +465,11 @@
 #ifndef PySet_CheckExact
   #define PySet_CheckExact(obj)        (Py_TYPE(obj) == &PySet_Type)
 #endif
-#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
+#if CYTHON_ASSUME_SAFE_MACROS
+  #define __Pyx_PySequence_SIZE(seq)  Py_SIZE(seq)
+#else
+  #define __Pyx_PySequence_SIZE(seq)  PySequence_Size(seq)
+#endif
 #if PY_MAJOR_VERSION >= 3
   #define PyIntObject                  PyLongObject
   #define PyInt_Type                   PyLong_Type
@@ -367,16 +504,10 @@
   #define __Pyx_PyInt_AsHash_t   PyInt_AsSsize_t
 #endif
 #if PY_MAJOR_VERSION >= 3
-  #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func))
+  #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func))
 #else
   #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
 #endif
-#ifndef __has_attribute
-  #define __has_attribute(x) 0
-#endif
-#ifndef __has_cpp_attribute
-  #define __has_cpp_attribute(x) 0
-#endif
 #if CYTHON_USE_ASYNC_SLOTS
   #if PY_VERSION_HEX >= 0x030500B1
     #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
@@ -394,96 +525,6 @@
         unaryfunc am_anext;
     } __Pyx_PyAsyncMethodsStruct;
 #endif
-#ifndef CYTHON_RESTRICT
-  #if defined(__GNUC__)
-    #define CYTHON_RESTRICT __restrict__
-  #elif defined(_MSC_VER) && _MSC_VER >= 1400
-    #define CYTHON_RESTRICT __restrict
-  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-    #define CYTHON_RESTRICT restrict
-  #else
-    #define CYTHON_RESTRICT
-  #endif
-#endif
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-#     define CYTHON_UNUSED __attribute__ ((__unused__))
-#   else
-#     define CYTHON_UNUSED
-#   endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-#   define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-#   define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_MAYBE_UNUSED_VAR
-#  if defined(__cplusplus)
-     template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
-#  else
-#    define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
-#  endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-#  define CYTHON_NCP_UNUSED
-# else
-#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
-#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
-#ifdef _MSC_VER
-    #ifndef _MSC_STDINT_H_
-        #if _MSC_VER < 1300
-           typedef unsigned char     uint8_t;
-           typedef unsigned int      uint32_t;
-        #else
-           typedef unsigned __int8   uint8_t;
-           typedef unsigned __int32  uint32_t;
-        #endif
-    #endif
-#else
-   #include <stdint.h>
-#endif
-#ifndef CYTHON_FALLTHROUGH
-  #if defined(__cplusplus) && __cplusplus >= 201103L
-    #if __has_cpp_attribute(fallthrough)
-      #define CYTHON_FALLTHROUGH [[fallthrough]]
-    #elif __has_cpp_attribute(clang::fallthrough)
-      #define CYTHON_FALLTHROUGH [[clang::fallthrough]]
-    #elif __has_cpp_attribute(gnu::fallthrough)
-      #define CYTHON_FALLTHROUGH [[gnu::fallthrough]]
-    #endif
-  #endif
-  #ifndef CYTHON_FALLTHROUGH
-    #if __has_attribute(fallthrough)
-      #define CYTHON_FALLTHROUGH __attribute__((fallthrough))
-    #else
-      #define CYTHON_FALLTHROUGH
-    #endif
-  #endif
-  #if defined(__clang__ ) && defined(__apple_build_version__)
-    #if __apple_build_version__ < 7000000
-      #undef  CYTHON_FALLTHROUGH
-      #define CYTHON_FALLTHROUGH
-    #endif
-  #endif
-#endif
-
-#ifndef CYTHON_INLINE
-  #if defined(__clang__)
-    #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
-  #elif defined(__GNUC__)
-    #define CYTHON_INLINE __inline__
-  #elif defined(_MSC_VER)
-    #define CYTHON_INLINE __inline
-  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-    #define CYTHON_INLINE inline
-  #else
-    #define CYTHON_INLINE
-  #endif
-#endif
 
 #if defined(WIN32) || defined(MS_WINDOWS)
   #define _USE_MATH_DEFINES
@@ -520,6 +561,7 @@ static CYTHON_INLINE float __PYX_NAN() {
 
 #define __PYX_HAVE__pssh__native___ssh2
 #define __PYX_HAVE_API__pssh__native___ssh2
+/* Early includes */
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -613,7 +655,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) {
 #define __Pyx_PyUnicode_AsUnicode            PyUnicode_AsUnicode
 #define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
 #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
-#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b);
 static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 #define __Pyx_PySequence_Tuple(obj)\
@@ -721,7 +763,7 @@ static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; }
 static PyObject *__pyx_m = NULL;
 static PyObject *__pyx_d;
 static PyObject *__pyx_b;
-static PyObject *__pyx_cython_runtime;
+static PyObject *__pyx_cython_runtime = NULL;
 static PyObject *__pyx_empty_tuple;
 static PyObject *__pyx_empty_bytes;
 static PyObject *__pyx_empty_unicode;
@@ -782,7 +824,6 @@ struct __pyx_obj_4ssh2_7session_Session {
  */
 struct __pyx_obj_4ssh2_4sftp_SFTP {
   PyObject_HEAD
-  struct __pyx_vtabstruct_4ssh2_4sftp_SFTP *__pyx_vtab;
   LIBSSH2_SFTP *_sftp;
   struct __pyx_obj_4ssh2_7session_Session *_session;
 };
@@ -853,20 +894,6 @@ struct __pyx_obj_4pssh_6native_5_ssh2___pyx_scope_struct___read_output {
 };
 
 
-
-/* "sftp.pxd":26
- * 
- * 
- * cdef class SFTP:             # <<<<<<<<<<<<<<
- *     cdef c_sftp.LIBSSH2_SFTP *_sftp
- *     cdef Session _session
- */
-
-struct __pyx_vtabstruct_4ssh2_4sftp_SFTP {
-  int (*_handle_error)(struct __pyx_obj_4ssh2_4sftp_SFTP *, int, PyObject *);
-};
-static struct __pyx_vtabstruct_4ssh2_4sftp_SFTP *__pyx_vtabptr_4ssh2_4sftp_SFTP;
-
 /* --- Runtime support code (head) --- */
 /* Refnanny.proto */
 #ifndef CYTHON_REFNANNY
@@ -933,16 +960,7 @@ static struct __pyx_vtabstruct_4ssh2_4sftp_SFTP *__pyx_vtabptr_4ssh2_4sftp_SFTP;
 
 /* PyObjectGetAttrStr.proto */
 #if CYTHON_USE_TYPE_SLOTS
-static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
-    PyTypeObject* tp = Py_TYPE(obj);
-    if (likely(tp->tp_getattro))
-        return tp->tp_getattro(obj, attr_name);
-#if PY_MAJOR_VERSION < 3
-    if (likely(tp->tp_getattr))
-        return tp->tp_getattr(obj, PyString_AS_STRING(attr_name));
-#endif
-    return PyObject_GetAttr(obj, attr_name);
-}
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name);
 #else
 #define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
 #endif
@@ -1092,8 +1110,12 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
 /* IncludeStringH.proto */
 #include <string.h>
 
-/* GetVTable.proto */
-static void* __Pyx_GetVtable(PyObject *dict);
+/* PyObject_GenericGetAttrNoDict.proto */
+#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name);
+#else
+#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr
+#endif
 
 /* Import.proto */
 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level);
@@ -1153,6 +1175,7 @@ static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObj
 #define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type)
 #define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2))
 #endif
+#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
 
 /* FetchCommonType.proto */
 static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type);
@@ -1176,14 +1199,15 @@ typedef struct {
     PyObject *gi_name;
     PyObject *gi_qualname;
     PyObject *gi_modulename;
+    PyObject *gi_code;
     int resume_label;
     char is_running;
 } __pyx_CoroutineObject;
 static __pyx_CoroutineObject *__Pyx__Coroutine_New(
-    PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *closure,
+    PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure,
     PyObject *name, PyObject *qualname, PyObject *module_name);
 static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
-            __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *closure,
+            __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure,
             PyObject *name, PyObject *qualname, PyObject *module_name);
 static int __Pyx_Coroutine_clear(PyObject *self);
 static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value);
@@ -1217,8 +1241,8 @@ static int __Pyx_patch_abc(void);
 #define __Pyx_Generator_USED
 static PyTypeObject *__pyx_GeneratorType = 0;
 #define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
-#define __Pyx_Generator_New(body, closure, name, qualname, module_name)\
-    __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname, module_name)
+#define __Pyx_Generator_New(body, code, closure, name, qualname, module_name)\
+    __Pyx__Coroutine_New(__pyx_GeneratorType, body, code, closure, name, qualname, module_name)
 static PyObject *__Pyx_Generator_Next(PyObject *self);
 static int __pyx_Generator_init(void);
 
@@ -1291,8 +1315,8 @@ int __pyx_module_is_main_pssh__native___ssh2 = 0;
 static PyObject *__pyx_builtin_OSError;
 static PyObject *__pyx_builtin_MemoryError;
 static PyObject *__pyx_builtin_IOError;
-static const char __pyx_k_[] = "";
-static const char __pyx_k__4[] = "\n";
+static const char __pyx_k__2[] = "";
+static const char __pyx_k__5[] = "\n";
 static const char __pyx_k_rc[] = "rc";
 static const char __pyx_k_pos[] = "_pos";
 static const char __pyx_k_ptr[] = "ptr";
@@ -1327,9 +1351,7 @@ static const char __pyx_k_remainder[] = "remainder";
 static const char __pyx_k_session_2[] = "_session";
 static const char __pyx_k_exceptions[] = "exceptions";
 static const char __pyx_k_local_file[] = "local_file";
-static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__";
 static const char __pyx_k_MemoryError[] = "MemoryError";
-static const char __pyx_k_SFTPIOError[] = "SFTPIOError";
 static const char __pyx_k_read_output[] = "_read_output";
 static const char __pyx_k_wait_select[] = "wait_select";
 static const char __pyx_k_SessionError[] = "SessionError";
@@ -1338,19 +1360,20 @@ static const char __pyx_k_local_file_2[] = "_local_file";
 static const char __pyx_k_buffer_maxlen[] = "buffer_maxlen";
 static const char __pyx_k_gevent_select[] = "gevent.select";
 static const char __pyx_k_remainder_len[] = "remainder_len";
+static const char __pyx_k_SFTPHandleError[] = "SFTPHandleError";
 static const char __pyx_k_ssh2_exceptions[] = "ssh2.exceptions";
 static const char __pyx_k_pssh_native__ssh2[] = "pssh.native._ssh2";
 static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
 static const char __pyx_k_pssh_native__ssh2_pyx[] = "pssh/native/_ssh2.pyx";
 static const char __pyx_k_Cython_functions_for_interfacing[] = "Cython functions for interfacing directly with ssh2-python's C-API";
-static PyObject *__pyx_kp_b_;
 static PyObject *__pyx_n_s_IOError;
 static PyObject *__pyx_n_s_MemoryError;
 static PyObject *__pyx_n_s_OSError;
-static PyObject *__pyx_n_s_SFTPIOError;
+static PyObject *__pyx_n_s_SFTPHandleError;
 static PyObject *__pyx_n_s_SessionError;
 static PyObject *__pyx_n_s_Timeout;
-static PyObject *__pyx_kp_b__4;
+static PyObject *__pyx_kp_b__2;
+static PyObject *__pyx_kp_b__5;
 static PyObject *__pyx_n_s_args;
 static PyObject *__pyx_n_s_b_local_file;
 static PyObject *__pyx_n_s_buffer_maxlen;
@@ -1374,7 +1397,6 @@ static PyObject *__pyx_n_s_pos;
 static PyObject *__pyx_n_s_pssh_native__ssh2;
 static PyObject *__pyx_kp_s_pssh_native__ssh2_pyx;
 static PyObject *__pyx_n_s_ptr;
-static PyObject *__pyx_n_s_pyx_vtable;
 static PyObject *__pyx_n_s_rc;
 static PyObject *__pyx_n_s_read_func;
 static PyObject *__pyx_n_s_read_output;
@@ -1399,16 +1421,17 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
 static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_4ssh2_7session_Session *__pyx_v_session, struct __pyx_obj_4ssh2_11sftp_handle_SFTPHandle *__pyx_v_handle, PyObject *__pyx_v_local_file, size_t __pyx_v_buffer_maxlen); /* proto */
 static PyObject *__pyx_pf_4pssh_6native_5_ssh2_7wait_select(CYTHON_UNUSED PyObject *__pyx_self, struct __pyx_obj_4ssh2_7session_Session *__pyx_v_session, PyObject *__pyx_v_timeout); /* proto */
 static PyObject *__pyx_tp_new_4pssh_6native_5_ssh2___pyx_scope_struct___read_output(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static size_t __pyx_k__2;
 static size_t __pyx_k__3;
-static PyObject *__pyx_tuple__5;
+static size_t __pyx_k__4;
+static PyObject *__pyx_codeobj_;
+static PyObject *__pyx_tuple__6;
 static PyObject *__pyx_tuple__7;
 static PyObject *__pyx_tuple__9;
 static PyObject *__pyx_tuple__11;
-static PyObject *__pyx_codeobj__6;
 static PyObject *__pyx_codeobj__8;
 static PyObject *__pyx_codeobj__10;
 static PyObject *__pyx_codeobj__12;
+/* Late includes */
 static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject *__pyx_generator, CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject *__pyx_sent_value); /* proto */
 
 /* "pssh/native/_ssh2.pyx":42
@@ -1450,18 +1473,18 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_1_read_output(PyObject *__pyx_sel
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
+        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
-        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_read_func)) != 0)) kw_args--;
+        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_read_func)) != 0)) kw_args--;
         else {
           __Pyx_RaiseArgtupleInvalid("_read_output", 0, 2, 3, 1); __PYX_ERR(0, 42, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
         if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_timeout);
+          PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_timeout);
           if (value) { values[2] = value; kw_args--; }
         }
       }
@@ -1525,7 +1548,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2__read_output(CYTHON_UNUSED PyObje
   __Pyx_INCREF(__pyx_cur_scope->__pyx_v_timeout);
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_timeout);
   {
-    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_4pssh_6native_5_ssh2_2generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_read_output, __pyx_n_s_read_output, __pyx_n_s_pssh_native__ssh2); if (unlikely(!gen)) __PYX_ERR(0, 42, __pyx_L1_error)
+    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_4pssh_6native_5_ssh2_2generator, __pyx_codeobj_, (PyObject *) __pyx_cur_scope, __pyx_n_s_read_output, __pyx_n_s_read_output, __pyx_n_s_pssh_native__ssh2); if (unlikely(!gen)) __PYX_ERR(0, 42, __pyx_L1_error)
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -1578,9 +1601,9 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
  *     cdef Py_ssize_t remainder_len = 0
  *     cdef LIBSSH2_SESSION *_session = session._session
  */
-  __Pyx_INCREF(__pyx_kp_b_);
-  __Pyx_GIVEREF(__pyx_kp_b_);
-  __pyx_cur_scope->__pyx_v_remainder = __pyx_kp_b_;
+  __Pyx_INCREF(__pyx_kp_b__2);
+  __Pyx_GIVEREF(__pyx_kp_b__2);
+  __pyx_cur_scope->__pyx_v_remainder = __pyx_kp_b__2;
 
   /* "pssh/native/_ssh2.pyx":46
  *     cdef bytes _data
@@ -1648,11 +1671,7 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) {
     PyObject* sequence = __pyx_t_3;
-    #if !CYTHON_COMPILING_IN_PYPY
-    Py_ssize_t size = Py_SIZE(sequence);
-    #else
-    Py_ssize_t size = PySequence_Size(sequence);
-    #endif
+    Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
     if (unlikely(size != 2)) {
       if (size > 2) __Pyx_RaiseTooManyValuesError(2);
       else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
@@ -1770,11 +1789,7 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
       if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) {
         PyObject* sequence = __pyx_t_3;
-        #if !CYTHON_COMPILING_IN_PYPY
-        Py_ssize_t size = Py_SIZE(sequence);
-        #else
-        Py_ssize_t size = PySequence_Size(sequence);
-        #endif
+        Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
         if (unlikely(size != 2)) {
           if (size > 2) __Pyx_RaiseTooManyValuesError(2);
           else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
@@ -1844,7 +1859,7 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
       __pyx_t_11 = ((__pyx_cur_scope->__pyx_v__size == LIBSSH2_ERROR_EAGAIN) != 0);
       __pyx_t_9 = __pyx_t_11;
       __pyx_L14_bool_binop_done:;
-      if (__pyx_t_9) {
+      if (unlikely(__pyx_t_9)) {
 
         /* "pssh/native/_ssh2.pyx":57
  *             _size, _data = read_func()
@@ -2043,10 +2058,10 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
  *                         remainder_len = 0
  *                     else:
  */
-            __Pyx_INCREF(__pyx_kp_b_);
+            __Pyx_INCREF(__pyx_kp_b__2);
             __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_remainder);
-            __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_remainder, __pyx_kp_b_);
-            __Pyx_GIVEREF(__pyx_kp_b_);
+            __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_remainder, __pyx_kp_b__2);
+            __Pyx_GIVEREF(__pyx_kp_b__2);
 
             /* "pssh/native/_ssh2.pyx":65
  *                         yield remainder + _data[_pos:linesep].rstrip()
@@ -2207,11 +2222,7 @@ static PyObject *__pyx_gb_4pssh_6native_5_ssh2_2generator(__pyx_CoroutineObject
       __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
       if ((likely(PyTuple_CheckExact(__pyx_t_5))) || (PyList_CheckExact(__pyx_t_5))) {
         PyObject* sequence = __pyx_t_5;
-        #if !CYTHON_COMPILING_IN_PYPY
-        Py_ssize_t size = Py_SIZE(sequence);
-        #else
-        Py_ssize_t size = PySequence_Size(sequence);
-        #endif
+        Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
         if (unlikely(size != 2)) {
           if (size > 2) __Pyx_RaiseTooManyValuesError(2);
           else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
@@ -2381,24 +2392,24 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_4sftp_put(PyObject *__pyx_self, P
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
+        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
-        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_handle)) != 0)) kw_args--;
+        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_handle)) != 0)) kw_args--;
         else {
           __Pyx_RaiseArgtupleInvalid("sftp_put", 0, 3, 4, 1); __PYX_ERR(0, 80, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
-        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_local_file)) != 0)) kw_args--;
+        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_local_file)) != 0)) kw_args--;
         else {
           __Pyx_RaiseArgtupleInvalid("sftp_put", 0, 3, 4, 2); __PYX_ERR(0, 80, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  3:
         if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_buffer_maxlen);
+          PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_buffer_maxlen);
           if (value) { values[3] = value; kw_args--; }
         }
       }
@@ -2422,7 +2433,7 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_4sftp_put(PyObject *__pyx_self, P
     if (values[3]) {
       __pyx_v_buffer_maxlen = __Pyx_PyInt_As_size_t(values[3]); if (unlikely((__pyx_v_buffer_maxlen == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 81, __pyx_L3_error)
     } else {
-      __pyx_v_buffer_maxlen = __pyx_k__2;
+      __pyx_v_buffer_maxlen = __pyx_k__3;
     }
   }
   goto __pyx_L4_argument_unpacking_done;
@@ -2917,7 +2928,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  *                     rc = libssh2_sftp_write(_handle, ptr, nread)
  *                 if rc < 0:             # <<<<<<<<<<<<<<
  *                     with gil:
- *                         raise SFTPIOError(rc)
+ *                         raise SFTPHandleError(rc)
  */
             __pyx_t_6 = ((__pyx_v_rc < 0) != 0);
             if (__pyx_t_6) {
@@ -2926,7 +2937,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  *                     rc = libssh2_sftp_write(_handle, ptr, nread)
  *                 if rc < 0:
  *                     with gil:             # <<<<<<<<<<<<<<
- *                         raise SFTPIOError(rc)
+ *                         raise SFTPHandleError(rc)
  *                 nread = fread(cbuf, 1, buffer_maxlen, local_fh)
  */
               {
@@ -2938,11 +2949,11 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
                     /* "pssh/native/_ssh2.pyx":121
  *                 if rc < 0:
  *                     with gil:
- *                         raise SFTPIOError(rc)             # <<<<<<<<<<<<<<
+ *                         raise SFTPHandleError(rc)             # <<<<<<<<<<<<<<
  *                 nread = fread(cbuf, 1, buffer_maxlen, local_fh)
  *         finally:
  */
-                    __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_SFTPIOError); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 121, __pyx_L37_error)
+                    __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_SFTPHandleError); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 121, __pyx_L37_error)
                     __Pyx_GOTREF(__pyx_t_8);
                     __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_rc); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 121, __pyx_L37_error)
                     __Pyx_GOTREF(__pyx_t_9);
@@ -3001,7 +3012,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  *                     rc = libssh2_sftp_write(_handle, ptr, nread)
  *                 if rc < 0:
  *                     with gil:             # <<<<<<<<<<<<<<
- *                         raise SFTPIOError(rc)
+ *                         raise SFTPHandleError(rc)
  *                 nread = fread(cbuf, 1, buffer_maxlen, local_fh)
  */
                   /*finally:*/ {
@@ -3019,13 +3030,13 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  *                     rc = libssh2_sftp_write(_handle, ptr, nread)
  *                 if rc < 0:             # <<<<<<<<<<<<<<
  *                     with gil:
- *                         raise SFTPIOError(rc)
+ *                         raise SFTPHandleError(rc)
  */
             }
 
             /* "pssh/native/_ssh2.pyx":122
  *                     with gil:
- *                         raise SFTPIOError(rc)
+ *                         raise SFTPHandleError(rc)
  *                 nread = fread(cbuf, 1, buffer_maxlen, local_fh)             # <<<<<<<<<<<<<<
  *         finally:
  *             free(cbuf)
@@ -3052,7 +3063,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  * 
  * 
  */
-            fclose(__pyx_v_local_fh);
+            (void)(fclose(__pyx_v_local_fh));
             goto __pyx_L16;
           }
           __pyx_L15_error:;
@@ -3101,7 +3112,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_3sftp_put(CYTHON_UNUSED PyObject
  * 
  * 
  */
-              fclose(__pyx_v_local_fh);
+              (void)(fclose(__pyx_v_local_fh));
             }
             #ifdef WITH_THREAD
             __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
@@ -3220,24 +3231,24 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_6sftp_get(PyObject *__pyx_self, P
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
+        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
-        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_handle)) != 0)) kw_args--;
+        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_handle)) != 0)) kw_args--;
         else {
           __Pyx_RaiseArgtupleInvalid("sftp_get", 0, 3, 4, 1); __PYX_ERR(0, 128, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  2:
-        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_local_file)) != 0)) kw_args--;
+        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_local_file)) != 0)) kw_args--;
         else {
           __Pyx_RaiseArgtupleInvalid("sftp_get", 0, 3, 4, 2); __PYX_ERR(0, 128, __pyx_L3_error)
         }
         CYTHON_FALLTHROUGH;
         case  3:
         if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_buffer_maxlen);
+          PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_buffer_maxlen);
           if (value) { values[3] = value; kw_args--; }
         }
       }
@@ -3261,7 +3272,7 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_6sftp_get(PyObject *__pyx_self, P
     if (values[3]) {
       __pyx_v_buffer_maxlen = __Pyx_PyInt_As_size_t(values[3]); if (unlikely((__pyx_v_buffer_maxlen == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 129, __pyx_L3_error)
     } else {
-      __pyx_v_buffer_maxlen = __pyx_k__3;
+      __pyx_v_buffer_maxlen = __pyx_k__4;
     }
   }
   goto __pyx_L4_argument_unpacking_done;
@@ -3717,9 +3728,9 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject
  *             free(cbuf)
  *             fclose(local_fh)             # <<<<<<<<<<<<<<
  *     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:
- *         raise SFTPIOError(rc)
+ *         raise SFTPHandleError(rc)
  */
-            fclose(__pyx_v_local_fh);
+            (void)(fclose(__pyx_v_local_fh));
             goto __pyx_L16;
           }
           __pyx_L15_error:;
@@ -3762,9 +3773,9 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject
  *             free(cbuf)
  *             fclose(local_fh)             # <<<<<<<<<<<<<<
  *     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:
- *         raise SFTPIOError(rc)
+ *         raise SFTPHandleError(rc)
  */
-              fclose(__pyx_v_local_fh);
+              (void)(fclose(__pyx_v_local_fh));
             }
             #ifdef WITH_THREAD
             __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
@@ -3820,7 +3831,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject
  *             free(cbuf)
  *             fclose(local_fh)
  *     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:             # <<<<<<<<<<<<<<
- *         raise SFTPIOError(rc)
+ *         raise SFTPHandleError(rc)
  * 
  */
   __pyx_t_7 = ((__pyx_v_rc < 0) != 0);
@@ -3832,16 +3843,16 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject
   __pyx_t_7 = ((__pyx_v_rc != LIBSSH2_ERROR_EAGAIN) != 0);
   __pyx_t_6 = __pyx_t_7;
   __pyx_L35_bool_binop_done:;
-  if (__pyx_t_6) {
+  if (unlikely(__pyx_t_6)) {
 
     /* "pssh/native/_ssh2.pyx":163
  *             fclose(local_fh)
  *     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:
- *         raise SFTPIOError(rc)             # <<<<<<<<<<<<<<
+ *         raise SFTPHandleError(rc)             # <<<<<<<<<<<<<<
  * 
  * 
  */
-    __pyx_t_16 = __Pyx_GetModuleGlobalName(__pyx_n_s_SFTPIOError); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 163, __pyx_L1_error)
+    __pyx_t_16 = __Pyx_GetModuleGlobalName(__pyx_n_s_SFTPHandleError); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 163, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_16);
     __pyx_t_17 = __Pyx_PyInt_From_int(__pyx_v_rc); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 163, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_17);
@@ -3899,7 +3910,7 @@ static PyObject *__pyx_pf_4pssh_6native_5_ssh2_5sftp_get(CYTHON_UNUSED PyObject
  *             free(cbuf)
  *             fclose(local_fh)
  *     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:             # <<<<<<<<<<<<<<
- *         raise SFTPIOError(rc)
+ *         raise SFTPHandleError(rc)
  * 
  */
   }
@@ -4160,12 +4171,12 @@ static PyObject *__pyx_pw_4pssh_6native_5_ssh2_8wait_select(PyObject *__pyx_self
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
+        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_session)) != 0)) kw_args--;
         else goto __pyx_L5_argtuple_error;
         CYTHON_FALLTHROUGH;
         case  1:
         if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_timeout);
+          PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_timeout);
           if (value) { values[1] = value; kw_args--; }
         }
       }
@@ -4401,14 +4412,14 @@ static struct PyModuleDef __pyx_moduledef = {
 #endif
 
 static __Pyx_StringTabEntry __pyx_string_tab[] = {
-  {&__pyx_kp_b_, __pyx_k_, sizeof(__pyx_k_), 0, 0, 0, 0},
   {&__pyx_n_s_IOError, __pyx_k_IOError, sizeof(__pyx_k_IOError), 0, 0, 1, 1},
   {&__pyx_n_s_MemoryError, __pyx_k_MemoryError, sizeof(__pyx_k_MemoryError), 0, 0, 1, 1},
   {&__pyx_n_s_OSError, __pyx_k_OSError, sizeof(__pyx_k_OSError), 0, 0, 1, 1},
-  {&__pyx_n_s_SFTPIOError, __pyx_k_SFTPIOError, sizeof(__pyx_k_SFTPIOError), 0, 0, 1, 1},
+  {&__pyx_n_s_SFTPHandleError, __pyx_k_SFTPHandleError, sizeof(__pyx_k_SFTPHandleError), 0, 0, 1, 1},
   {&__pyx_n_s_SessionError, __pyx_k_SessionError, sizeof(__pyx_k_SessionError), 0, 0, 1, 1},
   {&__pyx_n_s_Timeout, __pyx_k_Timeout, sizeof(__pyx_k_Timeout), 0, 0, 1, 1},
-  {&__pyx_kp_b__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 0, 0, 0},
+  {&__pyx_kp_b__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 0, 0, 0},
+  {&__pyx_kp_b__5, __pyx_k__5, sizeof(__pyx_k__5), 0, 0, 0, 0},
   {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1},
   {&__pyx_n_s_b_local_file, __pyx_k_b_local_file, sizeof(__pyx_k_b_local_file), 0, 0, 1, 1},
   {&__pyx_n_s_buffer_maxlen, __pyx_k_buffer_maxlen, sizeof(__pyx_k_buffer_maxlen), 0, 0, 1, 1},
@@ -4432,7 +4443,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s_pssh_native__ssh2, __pyx_k_pssh_native__ssh2, sizeof(__pyx_k_pssh_native__ssh2), 0, 0, 1, 1},
   {&__pyx_kp_s_pssh_native__ssh2_pyx, __pyx_k_pssh_native__ssh2_pyx, sizeof(__pyx_k_pssh_native__ssh2_pyx), 0, 0, 1, 0},
   {&__pyx_n_s_ptr, __pyx_k_ptr, sizeof(__pyx_k_ptr), 0, 0, 1, 1},
-  {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1},
   {&__pyx_n_s_rc, __pyx_k_rc, sizeof(__pyx_k_rc), 0, 0, 1, 1},
   {&__pyx_n_s_read_func, __pyx_k_read_func, sizeof(__pyx_k_read_func), 0, 0, 1, 1},
   {&__pyx_n_s_read_output, __pyx_k_read_output, sizeof(__pyx_k_read_output), 0, 0, 1, 1},
@@ -4474,10 +4484,10 @@ static int __Pyx_InitCachedConstants(void) {
  *     cdef Py_ssize_t _size
  *     cdef bytes _data
  */
-  __pyx_tuple__5 = PyTuple_Pack(11, __pyx_n_s_session, __pyx_n_s_read_func, __pyx_n_s_timeout, __pyx_n_s_size, __pyx_n_s_data, __pyx_n_s_remainder, __pyx_n_s_remainder_len, __pyx_n_s_session_2, __pyx_n_s_sock, __pyx_n_s_pos, __pyx_n_s_linesep); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 42, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_tuple__5);
-  __Pyx_GIVEREF(__pyx_tuple__5);
-  __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(3, 0, 11, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_pssh_native__ssh2_pyx, __pyx_n_s_read_output, 42, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 42, __pyx_L1_error)
+  __pyx_tuple__6 = PyTuple_Pack(11, __pyx_n_s_session, __pyx_n_s_read_func, __pyx_n_s_timeout, __pyx_n_s_size, __pyx_n_s_data, __pyx_n_s_remainder, __pyx_n_s_remainder_len, __pyx_n_s_session_2, __pyx_n_s_sock, __pyx_n_s_pos, __pyx_n_s_linesep); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(0, 42, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_tuple__6);
+  __Pyx_GIVEREF(__pyx_tuple__6);
+  __pyx_codeobj_ = (PyObject*)__Pyx_PyCode_New(3, 0, 11, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__6, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_pssh_native__ssh2_pyx, __pyx_n_s_read_output, 42, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj_)) __PYX_ERR(0, 42, __pyx_L1_error)
 
   /* "pssh/native/_ssh2.pyx":80
  * 
@@ -4528,12 +4538,127 @@ static int __Pyx_InitGlobals(void) {
   return -1;
 }
 
+static int __Pyx_modinit_global_init_code(void); /*proto*/
+static int __Pyx_modinit_variable_export_code(void); /*proto*/
+static int __Pyx_modinit_function_export_code(void); /*proto*/
+static int __Pyx_modinit_type_init_code(void); /*proto*/
+static int __Pyx_modinit_type_import_code(void); /*proto*/
+static int __Pyx_modinit_variable_import_code(void); /*proto*/
+static int __Pyx_modinit_function_import_code(void); /*proto*/
+
+static int __Pyx_modinit_global_init_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0);
+  /*--- Global init code ---*/
+  __pyx_v_4pssh_6native_5_ssh2_LINESEP = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  __Pyx_RefNannyFinishContext();
+  return 0;
+}
+
+static int __Pyx_modinit_variable_export_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0);
+  /*--- Variable export code ---*/
+  __Pyx_RefNannyFinishContext();
+  return 0;
+}
+
+static int __Pyx_modinit_function_export_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0);
+  /*--- Function export code ---*/
+  __Pyx_RefNannyFinishContext();
+  return 0;
+}
+
+static int __Pyx_modinit_type_init_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0);
+  /*--- Type init code ---*/
+  if (PyType_Ready(&__pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output) < 0) __PYX_ERR(0, 42, __pyx_L1_error)
+  __pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output.tp_print = 0;
+  if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output.tp_dictoffset && __pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output.tp_getattro == PyObject_GenericGetAttr)) {
+    __pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict;
+  }
+  __pyx_ptype_4pssh_6native_5_ssh2___pyx_scope_struct___read_output = &__pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output;
+  __Pyx_RefNannyFinishContext();
+  return 0;
+  __pyx_L1_error:;
+  __Pyx_RefNannyFinishContext();
+  return -1;
+}
+
+static int __Pyx_modinit_type_import_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0);
+  /*--- Type import code ---*/
+  __pyx_ptype_4ssh2_7session_Session = __Pyx_ImportType("ssh2.session", "Session", sizeof(struct __pyx_obj_4ssh2_7session_Session), 1); if (unlikely(!__pyx_ptype_4ssh2_7session_Session)) __PYX_ERR(1, 19, __pyx_L1_error)
+  __pyx_ptype_4ssh2_4sftp_SFTP = __Pyx_ImportType("ssh2.sftp", "SFTP", sizeof(struct __pyx_obj_4ssh2_4sftp_SFTP), 1); if (unlikely(!__pyx_ptype_4ssh2_4sftp_SFTP)) __PYX_ERR(2, 26, __pyx_L1_error)
+  __pyx_ptype_4ssh2_11sftp_handle_SFTPHandle = __Pyx_ImportType("ssh2.sftp_handle", "SFTPHandle", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPHandle), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPHandle)) __PYX_ERR(3, 25, __pyx_L1_error)
+  __pyx_ptype_4ssh2_11sftp_handle_SFTPAttributes = __Pyx_ImportType("ssh2.sftp_handle", "SFTPAttributes", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPAttributes), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPAttributes)) __PYX_ERR(3, 31, __pyx_L1_error)
+  __pyx_ptype_4ssh2_11sftp_handle_SFTPStatVFS = __Pyx_ImportType("ssh2.sftp_handle", "SFTPStatVFS", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPStatVFS), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPStatVFS)) __PYX_ERR(3, 35, __pyx_L1_error)
+  __Pyx_RefNannyFinishContext();
+  return 0;
+  __pyx_L1_error:;
+  __Pyx_RefNannyFinishContext();
+  return -1;
+}
+
+static int __Pyx_modinit_variable_import_code(void) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0);
+  /*--- Variable import code ---*/
+  __Pyx_RefNannyFinishContext();
+  return 0;
+}
+
+static int __Pyx_modinit_function_import_code(void) {
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0);
+  /*--- Function import code ---*/
+  __pyx_t_1 = __Pyx_ImportModule("ssh2.utils"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error)
+  if (__Pyx_ImportFunction(__pyx_t_1, "to_bytes", (void (**)(void))&__pyx_f_4ssh2_5utils_to_bytes, "PyObject *(PyObject *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+  Py_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_RefNannyFinishContext();
+  return 0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+}
+
+
 #if PY_MAJOR_VERSION < 3
-PyMODINIT_FUNC init_ssh2(void); /*proto*/
-PyMODINIT_FUNC init_ssh2(void)
+#ifdef CYTHON_NO_PYINIT_EXPORT
+#define __Pyx_PyMODINIT_FUNC void
+#else
+#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC
+#endif
+#else
+#ifdef CYTHON_NO_PYINIT_EXPORT
+#define __Pyx_PyMODINIT_FUNC PyObject *
+#else
+#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC
+#endif
+#endif
+#ifndef CYTHON_SMALL_CODE
+#if defined(__clang__)
+    #define CYTHON_SMALL_CODE
+#elif defined(__GNUC__) && (!(defined(__cplusplus)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)))
+    #define CYTHON_SMALL_CODE __attribute__((optimize("Os")))
 #else
-PyMODINIT_FUNC PyInit__ssh2(void); /*proto*/
-PyMODINIT_FUNC PyInit__ssh2(void)
+    #define CYTHON_SMALL_CODE
+#endif
+#endif
+
+
+#if PY_MAJOR_VERSION < 3
+__Pyx_PyMODINIT_FUNC init_ssh2(void) CYTHON_SMALL_CODE; /*proto*/
+__Pyx_PyMODINIT_FUNC init_ssh2(void)
+#else
+__Pyx_PyMODINIT_FUNC PyInit__ssh2(void) CYTHON_SMALL_CODE; /*proto*/
+__Pyx_PyMODINIT_FUNC PyInit__ssh2(void)
 #if CYTHON_PEP489_MULTI_PHASE_INIT
 {
   return PyModuleDef_Init(&__pyx_moduledef);
@@ -4579,21 +4704,22 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
 {
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
   __Pyx_RefNannyDeclarations
   #if CYTHON_PEP489_MULTI_PHASE_INIT
   if (__pyx_m && __pyx_m == __pyx_pyinit_module) return 0;
+  #elif PY_MAJOR_VERSION >= 3
+  if (__pyx_m) return __Pyx_NewRef(__pyx_m);
   #endif
   #if CYTHON_REFNANNY
-  __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
-  if (!__Pyx_RefNanny) {
-      PyErr_Clear();
-      __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny");
-      if (!__Pyx_RefNanny)
-          Py_FatalError("failed to import 'refnanny' module");
-  }
-  #endif
-  __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit__ssh2(void)", 0);
+__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
+if (!__Pyx_RefNanny) {
+  PyErr_Clear();
+  __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny");
+  if (!__Pyx_RefNanny)
+      Py_FatalError("failed to import 'refnanny' module");
+}
+#endif
+  __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit__ssh2(void)", 0);
   if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error)
   __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error)
@@ -4663,26 +4789,14 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
   if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   /*--- Constants init code ---*/
   if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
-  /*--- Global init code ---*/
-  __pyx_v_4pssh_6native_5_ssh2_LINESEP = ((PyObject*)Py_None); Py_INCREF(Py_None);
-  /*--- Variable export code ---*/
-  /*--- Function export code ---*/
-  /*--- Type init code ---*/
-  if (PyType_Ready(&__pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output) < 0) __PYX_ERR(0, 42, __pyx_L1_error)
-  __pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output.tp_print = 0;
-  __pyx_ptype_4pssh_6native_5_ssh2___pyx_scope_struct___read_output = &__pyx_type_4pssh_6native_5_ssh2___pyx_scope_struct___read_output;
-  /*--- Type import code ---*/
-  __pyx_ptype_4ssh2_7session_Session = __Pyx_ImportType("ssh2.session", "Session", sizeof(struct __pyx_obj_4ssh2_7session_Session), 1); if (unlikely(!__pyx_ptype_4ssh2_7session_Session)) __PYX_ERR(1, 19, __pyx_L1_error)
-  __pyx_ptype_4ssh2_4sftp_SFTP = __Pyx_ImportType("ssh2.sftp", "SFTP", sizeof(struct __pyx_obj_4ssh2_4sftp_SFTP), 1); if (unlikely(!__pyx_ptype_4ssh2_4sftp_SFTP)) __PYX_ERR(2, 26, __pyx_L1_error)
-  __pyx_vtabptr_4ssh2_4sftp_SFTP = (struct __pyx_vtabstruct_4ssh2_4sftp_SFTP*)__Pyx_GetVtable(__pyx_ptype_4ssh2_4sftp_SFTP->tp_dict); if (unlikely(!__pyx_vtabptr_4ssh2_4sftp_SFTP)) __PYX_ERR(2, 26, __pyx_L1_error)
-  __pyx_ptype_4ssh2_11sftp_handle_SFTPHandle = __Pyx_ImportType("ssh2.sftp_handle", "SFTPHandle", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPHandle), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPHandle)) __PYX_ERR(3, 25, __pyx_L1_error)
-  __pyx_ptype_4ssh2_11sftp_handle_SFTPAttributes = __Pyx_ImportType("ssh2.sftp_handle", "SFTPAttributes", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPAttributes), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPAttributes)) __PYX_ERR(3, 31, __pyx_L1_error)
-  __pyx_ptype_4ssh2_11sftp_handle_SFTPStatVFS = __Pyx_ImportType("ssh2.sftp_handle", "SFTPStatVFS", sizeof(struct __pyx_obj_4ssh2_11sftp_handle_SFTPStatVFS), 1); if (unlikely(!__pyx_ptype_4ssh2_11sftp_handle_SFTPStatVFS)) __PYX_ERR(3, 35, __pyx_L1_error)
-  /*--- Variable import code ---*/
-  /*--- Function import code ---*/
-  __pyx_t_1 = __Pyx_ImportModule("ssh2.utils"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error)
-  if (__Pyx_ImportFunction(__pyx_t_1, "to_bytes", (void (**)(void))&__pyx_f_4ssh2_5utils_to_bytes, "PyObject *(PyObject *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error)
-  Py_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  /*--- Global type/function init code ---*/
+  (void)__Pyx_modinit_global_init_code();
+  (void)__Pyx_modinit_variable_export_code();
+  (void)__Pyx_modinit_function_export_code();
+  if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error;
+  if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error;
+  (void)__Pyx_modinit_variable_import_code();
+  if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error;
   /*--- Execution code ---*/
   #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
   if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
@@ -4695,40 +4809,40 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  * 
  * from ssh2.c_ssh2 cimport LIBSSH2_CHANNEL, LIBSSH2_SESSION_BLOCK_INBOUND, \
  */
-  __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__pyx_n_s_select);
   __Pyx_GIVEREF(__pyx_n_s_select);
-  PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_select);
-  __pyx_t_3 = __Pyx_Import(__pyx_n_s_gevent_select, __pyx_t_2, -1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_select); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)
+  PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_select);
+  __pyx_t_2 = __Pyx_Import(__pyx_n_s_gevent_select, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_select, __pyx_t_2) < 0) __PYX_ERR(0, 23, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_select); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_select, __pyx_t_1) < 0) __PYX_ERR(0, 23, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
   /* "pssh/native/_ssh2.pyx":33
  * from ssh2.session cimport Session
  * from ssh2.sftp_handle cimport SFTPHandle
- * from ssh2.exceptions import SFTPIOError             # <<<<<<<<<<<<<<
+ * from ssh2.exceptions import SFTPHandleError             # <<<<<<<<<<<<<<
  * from ssh2.utils cimport to_bytes
  * 
  */
-  __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 33, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_INCREF(__pyx_n_s_SFTPIOError);
-  __Pyx_GIVEREF(__pyx_n_s_SFTPIOError);
-  PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_SFTPIOError);
-  __pyx_t_2 = __Pyx_Import(__pyx_n_s_ssh2_exceptions, __pyx_t_3, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 33, __pyx_L1_error)
+  __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 33, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_SFTPIOError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 33, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_SFTPIOError, __pyx_t_3) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_INCREF(__pyx_n_s_SFTPHandleError);
+  __Pyx_GIVEREF(__pyx_n_s_SFTPHandleError);
+  PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_SFTPHandleError);
+  __pyx_t_1 = __Pyx_Import(__pyx_n_s_ssh2_exceptions, __pyx_t_2, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 33, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_SFTPHandleError); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 33, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_SFTPHandleError, __pyx_t_2) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /* "pssh/native/_ssh2.pyx":36
  * from ssh2.utils cimport to_bytes
@@ -4737,26 +4851,26 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  * 
  * 
  */
-  __pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyList_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__pyx_n_s_SessionError);
   __Pyx_GIVEREF(__pyx_n_s_SessionError);
-  PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_SessionError);
+  PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_SessionError);
   __Pyx_INCREF(__pyx_n_s_Timeout);
   __Pyx_GIVEREF(__pyx_n_s_Timeout);
-  PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_Timeout);
-  __pyx_t_3 = __Pyx_Import(__pyx_n_s_exceptions, __pyx_t_2, 2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 36, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_SessionError); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)
+  PyList_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_Timeout);
+  __pyx_t_2 = __Pyx_Import(__pyx_n_s_exceptions, __pyx_t_1, 2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_SessionError, __pyx_t_2) < 0) __PYX_ERR(0, 36, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Timeout); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Timeout, __pyx_t_2) < 0) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_SessionError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_SessionError, __pyx_t_1) < 0) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_Timeout); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Timeout, __pyx_t_1) < 0) __PYX_ERR(0, 36, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
   /* "pssh/native/_ssh2.pyx":39
  * 
@@ -4765,10 +4879,10 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  * 
  * 
  */
-  __Pyx_INCREF(__pyx_kp_b__4);
+  __Pyx_INCREF(__pyx_kp_b__5);
   __Pyx_XGOTREF(__pyx_v_4pssh_6native_5_ssh2_LINESEP);
-  __Pyx_DECREF_SET(__pyx_v_4pssh_6native_5_ssh2_LINESEP, __pyx_kp_b__4);
-  __Pyx_GIVEREF(__pyx_kp_b__4);
+  __Pyx_DECREF_SET(__pyx_v_4pssh_6native_5_ssh2_LINESEP, __pyx_kp_b__5);
+  __Pyx_GIVEREF(__pyx_kp_b__5);
 
   /* "pssh/native/_ssh2.pyx":42
  * 
@@ -4777,10 +4891,10 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *     cdef Py_ssize_t _size
  *     cdef bytes _data
  */
-  __pyx_t_3 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_1_read_output, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 42, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_read_output, __pyx_t_3) < 0) __PYX_ERR(0, 42, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_1_read_output, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 42, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_read_output, __pyx_t_2) < 0) __PYX_ERR(0, 42, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
   /* "pssh/native/_ssh2.pyx":81
  * 
@@ -4789,7 +4903,7 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *     """Native function for reading from SFTP and writing to local file"""
  *     cdef bytes b_local_file = to_bytes(local_file)
  */
-  __pyx_k__2 = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+  __pyx_k__3 = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
 
   /* "pssh/native/_ssh2.pyx":80
  * 
@@ -4798,10 +4912,10 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *              local_file, size_t buffer_maxlen=LIBSSH2_CHANNEL_WINDOW_DEFAULT):
  *     """Native function for reading from SFTP and writing to local file"""
  */
-  __pyx_t_3 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_4sftp_put, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 80, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sftp_put, __pyx_t_3) < 0) __PYX_ERR(0, 80, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_4sftp_put, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 80, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sftp_put, __pyx_t_2) < 0) __PYX_ERR(0, 80, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
   /* "pssh/native/_ssh2.pyx":129
  * 
@@ -4810,7 +4924,7 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *     """Native function for reading from local file and writing to SFTP"""
  *     cdef bytes b_local_file = to_bytes(local_file)
  */
-  __pyx_k__3 = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+  __pyx_k__4 = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
 
   /* "pssh/native/_ssh2.pyx":128
  * 
@@ -4819,10 +4933,10 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *              local_file, size_t buffer_maxlen=LIBSSH2_CHANNEL_WINDOW_DEFAULT):
  *     """Native function for reading from local file and writing to SFTP"""
  */
-  __pyx_t_3 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_6sftp_get, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 128, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sftp_get, __pyx_t_3) < 0) __PYX_ERR(0, 128, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_6sftp_get, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 128, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sftp_get, __pyx_t_2) < 0) __PYX_ERR(0, 128, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
   /* "pssh/native/_ssh2.pyx":180
  * 
@@ -4831,20 +4945,20 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
  *     cdef LIBSSH2_SESSION *_session = session._session
  *     cdef int _sock = session._sock
  */
-  __pyx_t_3 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_8wait_select, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 180, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_wait_select, __pyx_t_3) < 0) __PYX_ERR(0, 180, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_4pssh_6native_5_ssh2_8wait_select, NULL, __pyx_n_s_pssh_native__ssh2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 180, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_wait_select, __pyx_t_2) < 0) __PYX_ERR(0, 180, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
   /* "pssh/native/_ssh2.pyx":1
  * # This file is part of parallel-ssh.             # <<<<<<<<<<<<<<
  * 
  * # Copyright (C) 2014-2018 Panos Kittenis.
  */
-  __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
   /*--- Wrapped vars code ---*/
 
@@ -4852,7 +4966,6 @@ static int __pyx_pymod_exec__ssh2(PyObject *__pyx_pyinit_module)
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
   if (__pyx_m) {
     if (__pyx_d) {
       __Pyx_AddTraceback("init pssh.native._ssh2", 0, __pyx_lineno, __pyx_filename);
@@ -4890,6 +5003,20 @@ static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) {
 }
 #endif
 
+/* PyObjectGetAttrStr */
+#if CYTHON_USE_TYPE_SLOTS
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
+    PyTypeObject* tp = Py_TYPE(obj);
+    if (likely(tp->tp_getattro))
+        return tp->tp_getattro(obj, attr_name);
+#if PY_MAJOR_VERSION < 3
+    if (likely(tp->tp_getattr))
+        return tp->tp_getattr(obj, PyString_AS_STRING(attr_name));
+#endif
+    return PyObject_GetAttr(obj, attr_name);
+}
+#endif
+
 /* GetBuiltinName */
 static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
     PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name);
@@ -5375,10 +5502,19 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
   static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     PyObject *result;
 #if !CYTHON_AVOID_BORROWED_REFS
+#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1
+    result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash);
+    if (likely(result)) {
+        Py_INCREF(result);
+    } else if (unlikely(PyErr_Occurred())) {
+        result = NULL;
+    } else {
+#else
     result = PyDict_GetItem(__pyx_d, name);
     if (likely(result)) {
         Py_INCREF(result);
     } else {
+#endif
 #else
     result = PyObject_GetItem(__pyx_d, name);
     if (!result) {
@@ -5390,7 +5526,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
 }
 
 /* PyErrFetchRestore */
-    #if CYTHON_FAST_THREAD_STATE
+      #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     tmp_type = tstate->curexc_type;
@@ -5414,7 +5550,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject
 #endif
 
 /* RaiseException */
-    #if PY_MAJOR_VERSION < 3
+      #if PY_MAJOR_VERSION < 3
 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb,
                         CYTHON_UNUSED PyObject *cause) {
     __Pyx_PyThreadState_declare
@@ -5573,7 +5709,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject
 #endif
 
 /* GetException */
-    #if CYTHON_FAST_THREAD_STATE
+      #if CYTHON_FAST_THREAD_STATE
 static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
 #else
 static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
@@ -5643,7 +5779,7 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
 }
 
 /* SwapException */
-      #if CYTHON_FAST_THREAD_STATE
+        #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     #if PY_VERSION_HEX >= 0x030700A2
@@ -5677,7 +5813,7 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
 #endif
 
 /* SaveResetException */
-      #if CYTHON_FAST_THREAD_STATE
+        #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     #if PY_VERSION_HEX >= 0x030700A2
     *type = tstate->exc_state.exc_type;
@@ -5715,28 +5851,48 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
 }
 #endif
 
-/* GetVTable */
-      static void* __Pyx_GetVtable(PyObject *dict) {
-    void* ptr;
-    PyObject *ob = PyObject_GetItem(dict, __pyx_n_s_pyx_vtable);
-    if (!ob)
-        goto bad;
-#if PY_VERSION_HEX >= 0x02070000
-    ptr = PyCapsule_GetPointer(ob, 0);
+/* PyObject_GenericGetAttrNoDict */
+        #if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000
+static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) {
+    PyErr_Format(PyExc_AttributeError,
+#if PY_MAJOR_VERSION >= 3
+                 "'%.50s' object has no attribute '%U'",
+                 tp->tp_name, attr_name);
 #else
-    ptr = PyCObject_AsVoidPtr(ob);
+                 "'%.50s' object has no attribute '%.400s'",
+                 tp->tp_name, PyString_AS_STRING(attr_name));
 #endif
-    if (!ptr && !PyErr_Occurred())
-        PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type");
-    Py_DECREF(ob);
-    return ptr;
-bad:
-    Py_XDECREF(ob);
     return NULL;
 }
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) {
+    PyObject *descr;
+    PyTypeObject *tp = Py_TYPE(obj);
+    if (unlikely(!PyString_Check(attr_name))) {
+        return PyObject_GenericGetAttr(obj, attr_name);
+    }
+    assert(!tp->tp_dictoffset);
+    descr = _PyType_Lookup(tp, attr_name);
+    if (unlikely(!descr)) {
+        return __Pyx_RaiseGenericGetAttributeError(tp, attr_name);
+    }
+    Py_INCREF(descr);
+    #if PY_MAJOR_VERSION < 3
+    if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS)))
+    #endif
+    {
+        descrgetfunc f = Py_TYPE(descr)->tp_descr_get;
+        if (unlikely(f)) {
+            PyObject *res = f(descr, obj, (PyObject *)tp);
+            Py_DECREF(descr);
+            return res;
+        }
+    }
+    return descr;
+}
+#endif
 
 /* Import */
-      static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
+        static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
     PyObject *empty_list = 0;
     PyObject *module = 0;
     PyObject *global_dict = 0;
@@ -5801,7 +5957,7 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
 }
 
 /* ImportFrom */
-      static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) {
+        static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) {
     PyObject* value = __Pyx_PyObject_GetAttrStr(module, name);
     if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) {
         PyErr_Format(PyExc_ImportError,
@@ -5815,18 +5971,21 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
 }
 
 /* CLineInTraceback */
-      #ifndef CYTHON_CLINE_IN_TRACEBACK
+        #ifndef CYTHON_CLINE_IN_TRACEBACK
 static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_line) {
     PyObject *use_cline;
     PyObject *ptype, *pvalue, *ptraceback;
 #if CYTHON_COMPILING_IN_CPYTHON
     PyObject **cython_runtime_dict;
 #endif
+    if (unlikely(!__pyx_cython_runtime)) {
+        return c_line;
+    }
     __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback);
 #if CYTHON_COMPILING_IN_CPYTHON
     cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime);
     if (likely(cython_runtime_dict)) {
-      use_cline = PyDict_GetItem(*cython_runtime_dict, __pyx_n_s_cline_in_traceback);
+      use_cline = __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback);
     } else
 #endif
     {
@@ -5852,7 +6011,7 @@ static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_li
 #endif
 
 /* CodeObjectCache */
-      static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
+        static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
         return count;
@@ -5932,7 +6091,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
 }
 
 /* AddTraceback */
-      #include "compile.h"
+        #include "compile.h"
 #include "frameobject.h"
 #include "traceback.h"
 static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
@@ -6017,7 +6176,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* CIntFromPyVerify */
-      #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
+        #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0)
 #define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1)
@@ -6039,7 +6198,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
     }
 
 /* CIntToPy */
-      static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
+        static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
     const int neg_one = (int) -1, const_zero = (int) 0;
     const int is_unsigned = neg_one > const_zero;
     if (is_unsigned) {
@@ -6070,7 +6229,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* CIntFromPy */
-      static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) {
+        static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) {
     const size_t neg_one = (size_t) -1, const_zero = (size_t) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -6259,7 +6418,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* CIntToPy */
-      static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
+        static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
     const long neg_one = (long) -1, const_zero = (long) 0;
     const int is_unsigned = neg_one > const_zero;
     if (is_unsigned) {
@@ -6290,7 +6449,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* CIntFromPy */
-      static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
+        static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
     const long neg_one = (long) -1, const_zero = (long) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -6479,7 +6638,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* CIntFromPy */
-      static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
+        static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
     const int neg_one = (int) -1, const_zero = (int) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -6668,7 +6827,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
 }
 
 /* FastTypeChecks */
-      #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_COMPILING_IN_CPYTHON
 static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) {
     while (a) {
         a = a->tp_base;
@@ -6740,7 +6899,7 @@ static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObj
 #endif
 
 /* FetchCommonType */
-      static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
+        static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
     PyObject* fake_module;
     PyTypeObject* cached_type = NULL;
     fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI);
@@ -6779,7 +6938,7 @@ static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObj
 }
 
 /* PyObjectCallMethod1 */
-      static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
+        static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
     PyObject *result = NULL;
 #if CYTHON_UNPACK_METHODS
     if (likely(PyMethod_Check(method))) {
@@ -6821,17 +6980,16 @@ static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObj
     return result;
 }
 static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
-    PyObject *method, *result = NULL;
+    PyObject *method, *result;
     method = __Pyx_PyObject_GetAttrStr(obj, method_name);
-    if (unlikely(!method)) goto done;
+    if (unlikely(!method)) return NULL;
     result = __Pyx__PyObject_CallMethod1(method, arg);
-done:
-    Py_XDECREF(method);
+    Py_DECREF(method);
     return result;
 }
 
 /* CoroutineBase */
-      #include <structmember.h>
+        #include <structmember.h>
 #include <frameobject.h>
 #define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom)
 static int __Pyx_PyGen__FetchStopIterationValue(CYTHON_UNUSED PyThreadState *__pyx_tstate, PyObject **pvalue) {
@@ -6930,7 +7088,7 @@ static void __Pyx__Coroutine_AlreadyRunningError(CYTHON_UNUSED __pyx_CoroutineOb
     const char *msg;
     if (0) {
     #ifdef __Pyx_Coroutine_USED
-    } else if (__Pyx_Coroutine_CheckExact((PyObject*)gen)) {
+    } else if (__Pyx_Coroutine_Check((PyObject*)gen)) {
         msg = "coroutine already executing";
     #endif
     #ifdef __Pyx_AsyncGen_USED
@@ -6947,7 +7105,7 @@ static void __Pyx__Coroutine_NotStartedError(CYTHON_UNUSED PyObject *gen) {
     const char *msg;
     if (0) {
     #ifdef __Pyx_Coroutine_USED
-    } else if (__Pyx_Coroutine_CheckExact(gen)) {
+    } else if (__Pyx_Coroutine_Check(gen)) {
         msg = "can't send non-None value to a just-started coroutine";
     #endif
     #ifdef __Pyx_AsyncGen_USED
@@ -6962,7 +7120,7 @@ static void __Pyx__Coroutine_NotStartedError(CYTHON_UNUSED PyObject *gen) {
 #define __Pyx_Coroutine_AlreadyTerminatedError(gen, value, closing)  (__Pyx__Coroutine_AlreadyTerminatedError(gen, value, closing), (PyObject*)NULL)
 static void __Pyx__Coroutine_AlreadyTerminatedError(CYTHON_UNUSED PyObject *gen, PyObject *value, CYTHON_UNUSED int closing) {
     #ifdef __Pyx_Coroutine_USED
-    if (!closing && __Pyx_Coroutine_CheckExact(gen)) {
+    if (!closing && __Pyx_Coroutine_Check(gen)) {
         PyErr_SetString(PyExc_RuntimeError, "cannot reuse already awaited coroutine");
     } else
     #endif
@@ -7068,7 +7226,7 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
         } else
         #endif
         #ifdef __Pyx_Coroutine_USED
-        if (__Pyx_Coroutine_CheckExact(yf)) {
+        if (__Pyx_Coroutine_Check(yf)) {
             ret = __Pyx_Coroutine_Send(yf, value);
         } else
         #endif
@@ -7114,7 +7272,7 @@ static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) {
     } else
     #endif
     #ifdef __Pyx_Coroutine_USED
-    if (__Pyx_Coroutine_CheckExact(yf)) {
+    if (__Pyx_Coroutine_Check(yf)) {
         retval = __Pyx_Coroutine_Close(yf);
         if (!retval)
             return -1;
@@ -7170,6 +7328,11 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
         if (PyGen_CheckExact(yf)) {
             ret = _PyGen_Send((PyGenObject*)yf, NULL);
         } else
+        #endif
+        #ifdef __Pyx_Coroutine_USED
+        if (__Pyx_Coroutine_Check(yf)) {
+            ret = __Pyx_Coroutine_Send(yf, Py_None);
+        } else
         #endif
             ret = Py_TYPE(yf)->tp_iternext(yf);
         gen->is_running = 0;
@@ -7201,7 +7364,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
         Py_DECREF(retval);
         if ((0)) {
         #ifdef __Pyx_Coroutine_USED
-        } else if (__Pyx_Coroutine_CheckExact(self)) {
+        } else if (__Pyx_Coroutine_Check(self)) {
             msg = "coroutine ignored GeneratorExit";
         #endif
         #ifdef __Pyx_AsyncGen_USED
@@ -7249,7 +7412,7 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
             || __Pyx_Generator_CheckExact(yf)
         #endif
         #ifdef __Pyx_Coroutine_USED
-            || __Pyx_Coroutine_CheckExact(yf)
+            || __Pyx_Coroutine_Check(yf)
         #endif
             ) {
             ret = __Pyx__Coroutine_Throw(yf, typ, val, tb, args, close_on_genexit);
@@ -7318,6 +7481,7 @@ static int __Pyx_Coroutine_clear(PyObject *self) {
         Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer);
     }
 #endif
+    Py_CLEAR(gen->gi_code);
     Py_CLEAR(gen->gi_name);
     Py_CLEAR(gen->gi_qualname);
     Py_CLEAR(gen->gi_modulename);
@@ -7503,15 +7667,15 @@ __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
     return 0;
 }
 static __pyx_CoroutineObject *__Pyx__Coroutine_New(
-            PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *closure,
+            PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure,
             PyObject *name, PyObject *qualname, PyObject *module_name) {
     __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type);
     if (unlikely(!gen))
         return NULL;
-    return __Pyx__Coroutine_NewInit(gen, body, closure, name, qualname, module_name);
+    return __Pyx__Coroutine_NewInit(gen, body, code, closure, name, qualname, module_name);
 }
 static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
-            __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *closure,
+            __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure,
             PyObject *name, PyObject *qualname, PyObject *module_name) {
     gen->body = body;
     gen->closure = closure;
@@ -7530,12 +7694,14 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
     gen->gi_name = name;
     Py_XINCREF(module_name);
     gen->gi_modulename = module_name;
+    Py_XINCREF(code);
+    gen->gi_code = code;
     PyObject_GC_Track(gen);
     return gen;
 }
 
 /* PatchModuleWithCoroutine */
-          static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) {
+            static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) {
 #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
     int result;
     PyObject *globals, *result_obj;
@@ -7575,7 +7741,7 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
 }
 
 /* PatchGeneratorABC */
-          #ifndef CYTHON_REGISTER_ABCS
+            #ifndef CYTHON_REGISTER_ABCS
 #define CYTHON_REGISTER_ABCS 1
 #endif
 #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
@@ -7632,7 +7798,7 @@ static int __Pyx_patch_abc(void) {
 }
 
 /* Generator */
-          static PyMethodDef __pyx_Generator_methods[] = {
+            static PyMethodDef __pyx_Generator_methods[] = {
     {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O,
      (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")},
     {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS,
@@ -7645,6 +7811,7 @@ static PyMemberDef __pyx_Generator_memberlist[] = {
     {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL},
     {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY,
      (char*) PyDoc_STR("object being iterated by 'yield from', or None")},
+    {(char*) "gi_code", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_code), READONLY, NULL},
     {0, 0, 0, 0, 0}
 };
 static PyGetSetDef __pyx_Generator_getsets[] = {
@@ -7713,7 +7880,7 @@ static PyTypeObject __pyx_GeneratorType_type = {
 #endif
 };
 static int __pyx_Generator_init(void) {
-    __pyx_GeneratorType_type.tp_getattro = PyObject_GenericGetAttr;
+    __pyx_GeneratorType_type.tp_getattro = __Pyx_PyObject_GenericGetAttrNoDict;
     __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter;
     __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type);
     if (unlikely(!__pyx_GeneratorType)) {
@@ -7723,7 +7890,7 @@ static int __pyx_Generator_init(void) {
 }
 
 /* CheckBinaryVersion */
-          static int __Pyx_check_binary_version(void) {
+            static int __Pyx_check_binary_version(void) {
     char ctversion[4], rtversion[4];
     PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
     PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion());
@@ -7739,7 +7906,7 @@ static int __pyx_Generator_init(void) {
 }
 
 /* ModuleImport */
-          #ifndef __PYX_HAVE_RT_ImportModule
+            #ifndef __PYX_HAVE_RT_ImportModule
 #define __PYX_HAVE_RT_ImportModule
 static PyObject *__Pyx_ImportModule(const char *name) {
     PyObject *py_name = 0;
@@ -7757,7 +7924,7 @@ static PyObject *__Pyx_ImportModule(const char *name) {
 #endif
 
 /* TypeImport */
-          #ifndef __PYX_HAVE_RT_ImportType
+            #ifndef __PYX_HAVE_RT_ImportType
 #define __PYX_HAVE_RT_ImportType
 static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name,
     size_t size, int strict)
@@ -7822,7 +7989,7 @@ static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class
 #endif
 
 /* FunctionImport */
-          #ifndef __PYX_HAVE_RT_ImportFunction
+            #ifndef __PYX_HAVE_RT_ImportFunction
 #define __PYX_HAVE_RT_ImportFunction
 static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig) {
     PyObject *d = 0;
@@ -7876,7 +8043,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
 #endif
 
 /* InitStrings */
-          static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+            static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
     while (t->p) {
         #if PY_MAJOR_VERSION < 3
         if (t->is_unicode) {
@@ -7902,7 +8069,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
         if (!*t->p)
             return -1;
         if (PyObject_Hash(*t->p) == -1)
-            PyErr_Clear();
+            return -1;
         ++t;
     }
     return 0;
@@ -8116,6 +8283,9 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
   Py_DECREF(x);
   return ival;
 }
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) {
+  return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
+}
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
     return PyInt_FromSize_t(ival);
 }
diff --git a/pssh/native/_ssh2.pyx b/pssh/native/_ssh2.pyx
index 6bc2c61b..0eda181b 100644
--- a/pssh/native/_ssh2.pyx
+++ b/pssh/native/_ssh2.pyx
@@ -30,7 +30,7 @@ from ssh2.c_sftp cimport libssh2_sftp_read, libssh2_sftp_write, \
     LIBSSH2_SFTP_HANDLE
 from ssh2.session cimport Session
 from ssh2.sftp_handle cimport SFTPHandle
-from ssh2.exceptions import SFTPIOError
+from ssh2.exceptions import SFTPHandleError
 from ssh2.utils cimport to_bytes
 
 from ..exceptions import SessionError, Timeout
@@ -118,7 +118,7 @@ def sftp_put(Session session, SFTPHandle handle,
                     rc = libssh2_sftp_write(_handle, ptr, nread)
                 if rc < 0:
                     with gil:
-                        raise SFTPIOError(rc)
+                        raise SFTPHandleError(rc)
                 nread = fread(cbuf, 1, buffer_maxlen, local_fh)
         finally:
             free(cbuf)
@@ -160,7 +160,7 @@ def sftp_get(Session session, SFTPHandle handle,
             free(cbuf)
             fclose(local_fh)
     if rc < 0 and rc != LIBSSH2_ERROR_EAGAIN:
-        raise SFTPIOError(rc)
+        raise SFTPHandleError(rc)
 
 
 cdef int _wait_select(int _socket, LIBSSH2_SESSION *_session,
diff --git a/setup.py b/setup.py
index 5b083ff1..e8411fa7 100644
--- a/setup.py
+++ b/setup.py
@@ -39,9 +39,13 @@
                      'wraparound': False,
 }
 _embedded_lib = bool(int(os.environ.get('EMBEDDED_LIB', 1)))
+_have_agent_fwd = bool(int(os.environ.get('HAVE_AGENT_FWD', 1)))
 
 cython_args = {'cython_directives': cython_directives,
-               'cython_compile_time_env': {'EMBEDDED_LIB': _embedded_lib},
+               'cython_compile_time_env': {
+                   'EMBEDDED_LIB': _embedded_lib,
+                   'HAVE_AGENT_FWD': _have_agent_fwd,
+               },
 } if USING_CYTHON else {}
 
 _libs = ['ssh2'] if not ON_WINDOWS else [
@@ -90,7 +94,7 @@
                         'tests', 'tests.*',
                         '*.tests', '*.tests.*')
       ),
-      install_requires=['paramiko', gevent_req, 'ssh2-python>=0.12.0'],
+      install_requires=['paramiko', gevent_req, 'ssh2-python>=0.14.0'],
       classifiers=[
         'License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)',
         'Intended Audience :: Developers',
diff --git a/tests/base_ssh2_test.py b/tests/base_ssh2_test.py
index fd9701e2..a90b0dd9 100644
--- a/tests/base_ssh2_test.py
+++ b/tests/base_ssh2_test.py
@@ -7,7 +7,7 @@
 
 from .embedded_server.openssh import OpenSSHServer
 from ssh2.session import Session
-from pssh.ssh2_client import SSHClient, logger as ssh_logger
+from pssh.clients.native import SSHClient, logger as ssh_logger
 
 
 ssh_logger.setLevel(logging.DEBUG)
diff --git a/tests/test_native_parallel_client.py b/tests/test_native_parallel_client.py
index a57a41be..5d19752c 100644
--- a/tests/test_native_parallel_client.py
+++ b/tests/test_native_parallel_client.py
@@ -36,7 +36,7 @@
 
 
 import gevent
-from pssh.pssh2_client import ParallelSSHClient, logger as pssh_logger
+from pssh.clients.native import ParallelSSHClient, logger as pssh_logger
 from pssh.exceptions import UnknownHostException, \
     AuthenticationException, ConnectionErrorException, SessionError, \
     HostArgumentException, SFTPError, SFTPIOError, Timeout, SCPError, \
@@ -470,8 +470,11 @@ def test_pssh_client_directory_relative_path(self):
             for path in remote_file_paths:
                 self.assertTrue(os.path.isfile(path))
         finally:
-            shutil.rmtree(local_test_path)
-            shutil.rmtree(remote_test_path_abs)
+            try:
+                shutil.rmtree(local_test_path)
+                shutil.rmtree(remote_test_path_abs)
+            except Exception:
+                pass
 
     def test_pssh_client_directory_abs_path(self):
         client = ParallelSSHClient([self.host], port=self.port,
diff --git a/tests/test_native_single_client.py b/tests/test_native_single_client.py
index 515488a3..e789ecf9 100644
--- a/tests/test_native_single_client.py
+++ b/tests/test_native_single_client.py
@@ -8,7 +8,7 @@
 
 from .base_ssh2_test import SSH2TestCase
 from .embedded_server.openssh import OpenSSHServer
-from pssh.ssh2_client import SSHClient, logger as ssh_logger
+from pssh.clients.native import SSHClient, logger as ssh_logger
 from pssh.tunnel import Tunnel
 from ssh2.session import Session
 from pssh.exceptions import AuthenticationException, ConnectionErrorException, \